# Connect a synced item to an existing Jira Data Center issue (one to one and many to one)

**URL:** <https://community.exalate.com/t/connect-a-synced-item-to-an-existing-jira-data-center-issue-one-to-one-and-many-to-one/8460>\
**Category:** General Questions\
**Created:** [October 23, 2026, 6:33pm UTC](https://community.exalate.com/t/connect-a-synced-item-to-an-existing-jira-data-center-issue-one-to-one-and-many-to-one/8460 "2026-10-23T18:33:34Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Christophe\_De\_Beule](https://dub1.discourse-cdn.com/flex018/user_avatar/community.exalate.com/christophe_de_beule/32/472_2.png) [@Christophe\_De\_Beule](https://community.exalate.com/u/Christophe_De_Beule)\
**Post date:** [October 23, 2026, 6:33pm UTC](https://community.exalate.com/t/connect-a-synced-item-to-an-existing-jira-data-center-issue-one-to-one-and-many-to-one/8460/1 "2026-10-23T18:33:34Z")

</div>

**Platforms:** any → Jira Data Center

## The problem

By default, the first sync of a remote item creates a new issue in Jira. Often the issue already exists: it was created by hand before the integration, or several remote items belong to the same Jira issue. Creating a new issue then gives duplicates, and the team has to merge or close them by hand.

## The approach

1. **The remote side sends the Jira reference.** Its outgoing script puts the Jira ID (`12345`) or key (`PROJ-123`) in `replica.jiraId`.
2. **The Jira DC incoming script finds that issue on first sync.** A numeric value is looked up with `getIssueObject`, a key with `getIssueByCurrentKey`. If a reference is sent but the issue doesn’t exist, the sync stops with a clear error instead of creating a duplicate.
3. **The script connects to the existing issue instead of creating one.** It loads the issue as Exalate sees it, fills `issueBeforeScript` and `issue` with its current values, and sets `issue.id` and `issue.key` to the existing issue.
4. **Nothing sent: normal behavior.** Without a `jiraId`, a new issue is created in the default project, as usual.

## The result

- **One to one:** a remote item connects to the Jira issue it points to, no duplicate is created.
- **Many to one:** when another remote item arrives later with the same Jira ID or key, it connects to that same Jira issue as well.
- From then on, the items sync like any other pair.

## Notes

- Replace `PROJ` with your default project key, and fill `typemap` with your remote type names and the matching Jira issue types.
- The remote outgoing script must send the reference, for example `replica.jiraId = <the field that holds the Jira ID or key>`.
- `getIssueByCurrentKey` only accepts keys. A numeric Jira ID needs `getIssueObject(id as Long)`, which is why the script checks `isLong()` first.
- Maps are copied into `issue` (`new LinkedHashMap(v)`), so the changes made by the rest of your incoming script are detected as changes against `issueBeforeScript`.
- With many to one, all connected remote items update the same Jira issue. Keep that in mind for fields like summary or status, where the last update wins.
- Don’t have the ID or key on the remote side, only a value in a custom field? Find the issue with a JQL search first: [link to JQL post].
- Put your normal incoming mappings (summary, description, comments) below the connect block.

## The Scripts

**1. Jira DC incoming script: connect to an existing issue**

```java
// Exalate | Jira Data Center | Incoming sync
// On first sync, connect the remote item to an EXISTING Jira issue instead of creating a new one.
// Works one to one and many to one: every remote item that sends the same Jira ID or key
// is connected to that same Jira issue.
//
// The remote side sends the Jira ID (12345) or key (PROJ-123) in replica.jiraId.
// Nothing sent: a new issue is created in the default project.
//
// Configure:
// PROJECT_KEY default project for new issues
// typemap remote type name -> Jira issue type name
//
// Notes:
// - getIssueByCurrentKey() takes keys only; use getIssueObject(id as Long) for numeric IDs.
// - Maps are copied into "issue" so the rule's changes show up as diffs against issueBeforeScript.
import com.atlassian.jira.component.ComponentAccessor

final String PROJECT_KEY = "PROJ"

Map typemap = [
  "Bug": "Bug"
]

String typeName = typemap[replica.type?.name] ?: debug.error("Value ${replica.type?.name} Not found in type map.")

def issueManager = ComponentAccessor.issueManager
def mainIssue = null

// Find the existing Jira issue by the ID or key sent by the remote side
if (firstSync && replica.jiraId) {
    def ref = replica.jiraId.toString().trim() // Jira ID (12345) or key (PROJ-123)
    mainIssue = ref.isLong() ? issueManager.getIssueObject(ref as Long) : issueManager.getIssueByCurrentKey(ref)
    if (!mainIssue) {
        debug.error("Jira issue '${ref}' not found, cannot connect.")
    }
}

if (firstSync && mainIssue) {
    // Use the existing issue's project/type; fall back to defaults
    issue.projectKey = mainIssue.project?.key ?: PROJECT_KEY
    issue.typeName = mainIssue.issueType?.name ?: typeName

    // Load the existing Jira issue as Exalate sees it
    def issueKey = new com.exalate.basic.domain.BasicIssueKey(mainIssue.id, mainIssue.key)
    def hubObjectHelper = ComponentAccessor
        .getOSGiComponentInstanceOfType(com.exalate.api.hubobject.IHubObjectHelperFactory.class)
        .get(new com.exalate.basic.domain.BasicSemanticVersion(1, 0, 0))
    def hubIssue = hubObjectHelper.getHubIssueOnOutgoingProcessor(issueKey)

    // Fill "before" and "after"; Maps are copied so the rule's changes are detected as diffs
    hubIssue.getProperties().each { k, v ->
        issueBeforeScript[k] = v
        issue[k] = (v instanceof Map) ? new LinkedHashMap(v) : v
    }

    // Connect
    issueBeforeScript.id = null
    issue.id = mainIssue.id
    issue.key = mainIssue.key
    issue.customKeys.somethingIsChanged = true

} else if (firstSync) {
    issue.projectKey = PROJECT_KEY
    issue.typeName = typeName
}

// Your normal incoming mappings go below (summary, description, comments, ...)

```

---

<div class="post-metadata">

**Author:** ![Aida](https://dub1.discourse-cdn.com/flex018/user_avatar/community.exalate.com/aida/32/580_2.png) [@Aida](https://community.exalate.com/u/Aida)\
**Post date:** [October 23, 2026, 6:33pm UTC](https://community.exalate.com/t/connect-a-synced-item-to-an-existing-jira-data-center-issue-one-to-one-and-many-to-one/8460/2 "2026-10-23T18:33:41Z")

</div>

Great question! You’re absolutely right—by default, Exalate creates a new Jira issue on the first sync, which can lead to duplicates if the issue already exists or if multiple remote items should map to the same Jira issue. The approach you’ve outlined is a solid way to connect incoming remote items to an existing Jira Data Center issue, supporting both one-to-one and many-to-one relationships.

Here’s a summary of how to achieve this, along with the script you can use in your Jira Data Center incoming sync:

**How it works:**

- The remote side sends the Jira issue key or ID in a field (e.g., `replica.jiraId`).
- On the Jira DC side, the incoming sync script checks if this reference exists.
- If it does, the script looks up the existing issue (by key or ID), loads its current state, and connects the sync to that issue instead of creating a new one.
- If the reference isn’t found, the sync fails with a clear error, preventing duplicates.
- If no reference is sent, Exalate creates a new issue as usual.

**Key points:**

- This method supports both one-to-one and many-to-one mappings.
- All remote items referencing the same Jira issue will sync to that issue.
- Be mindful that with many-to-one, the last update wins for fields like summary or status.
- If you only have a custom field value (not the key or ID), you can use a JQL search to find the issue first.

**Sample Jira Data Center incoming sync script:**

```groovy
import com.atlassian.jira.component.ComponentAccessor

final String PROJECT_KEY = "PROJ" // Replace with your default project key

Map typemap = [
  "Bug": "Bug" // Map remote type names to Jira issue types
]

String typeName = typemap[replica.type?.name] ?: debug.error("Value ${replica.type?.name} Not found in type map.")

def issueManager = ComponentAccessor.issueManager
def mainIssue = null

// Find the existing Jira issue by the ID or key sent by the remote side
if (firstSync && replica.jiraId) {
    def ref = replica.jiraId.toString().trim() // Jira ID (12345) or key (PROJ-123)
    mainIssue = ref.isLong() ? issueManager.getIssueObject(ref as Long) : issueManager.getIssueByCurrentKey(ref)
    if (!mainIssue) {
        debug.error("Jira issue '${ref}' not found, cannot connect.")
    }
}

if (firstSync && mainIssue) {
    // Use the existing issue's project/type; fall back to defaults
    issue.projectKey = mainIssue.project?.key ?: PROJECT_KEY
    issue.typeName = mainIssue.issueType?.name ?: typeName

    // Load the existing Jira issue as Exalate sees it
    def issueKey = new com.exalate.basic.domain.BasicIssueKey(mainIssue.id, mainIssue.key)
    def hubObjectHelper = ComponentAccessor
        .getOSGiComponentInstanceOfType(com.exalate.api.hubobject.IHubObjectHelperFactory.class)
        .get(new com.exalate.basic.domain.BasicSemanticVersion(1, 0, 0))
    def hubIssue = hubObjectHelper.getHubIssueOnOutgoingProcessor(issueKey)

    // Fill "before" and "after"; Maps are copied so the rule's changes are detected as diffs
    hubIssue.getProperties().each { k, v ->
        issueBeforeScript[k] = v
        issue[k] = (v instanceof Map) ? new LinkedHashMap(v) : v
    }

    // Connect
    issueBeforeScript.id = null
    issue.id = mainIssue.id
    issue.key = mainIssue.key
    issue.customKeys.somethingIsChanged = true

} else if (firstSync) {
    issue.projectKey = PROJECT_KEY
    issue.typeName = typeName
}

// Your normal incoming mappings go below (summary, description, comments, ...)

```

**What to customize:**

- Replace `"PROJ"` with your default project key.
- Adjust the `typemap` to match your remote type names and Jira issue types.
- Make sure the remote outgoing script sends the Jira ID or key in `replica.jiraId`.

For more details and context, check out the official documentation:  
[https://docs.exalate.com/docs/connect-to-an-existing-jira-issue](https://docs.exalate.com/docs/connect-to-an-existing-jira-issue)

This approach should help you avoid duplicates and keep your syncs tidy, whether you’re mapping one or many remote items to a single Jira issue.
