👉 Join our Discord community to get the latest news, share ideas, and ask questions.

Query Adobe Campaign Classic v7 Data with JavaScript and queryDef

Highlight text, then choose “Suggest an edit”.Your selection is saved in the bottom bar.

Adobe Campaign Classic data-oriented APIs use schema-based XML to query and modify application data. In JavaScript, `xtk:queryDef` defines a query, and `ExecuteQuery()` returns its result as XML. The data-oriented API reference documents the query definition and session APIs.

Build a queryDef Selection

A query definition identifies the schema, operation, selected fields, and filter conditions. Create a selection with `xtk.queryDef.create`, then execute it with `ExecuteQuery()`:

var query = xtk.queryDef.create(
  <queryDef schema="nms:recipient" operation="select">
    <select>
      <node expr="@id"/>
      <node expr="@email"/>
      <node expr="@lastName"/>
    </select>
    <where>
      <condition expr="@email != ''"/>
    </where>
  </queryDef>
);

var results = query.ExecuteQuery();

The `schema` attribute identifies the Campaign schema. The `select` element specifies the attributes returned, and the `where` element filters the records before they are returned.

Use schema expressions, not physical database column names. In this example, `@email` and `@lastName` are attributes of `nms:recipient`. A field on a related schema requires the appropriate relationship expression.

TIP: There are a couple more ways to make the most of QueryDef

Process the XML Result in JavaScript

`ExecuteQuery()` returns XML containing the records and attributes selected by the query. The result can then be processed in an Adobe Campaign Classic JavaScript Code activity.

var recipients = results.recipient;

if (recipients.length() === 0) {
  logInfo("No recipients matched the query.");
} else {
  logInfo("Returned recipients: " + recipients.length());

  for each (var recipient in recipients) {
    var id = Number(recipient.@id);
    var email = String(recipient.@email);
    var lastName = String(recipient.@lastName);

    logInfo(
      "ID: " + id +
      ", email: " + email +
      ", last name: " + lastName
    );
  }
}

Select only the fields required by the next operation. A narrow query produces a smaller XML result and keeps the script focused on the values it actually uses.

You can also convert the selected records into JavaScript objects for further processing.

var recipients = results.recipient;

if (recipients.length() === 0) {
  logInfo("No recipients matched the query.");
} else {
  logInfo("Returned recipients: " + recipients.length());

  for each (var recipient in recipients) {
    var id = Number(recipient.@id);
    var email = String(recipient.@email);
    var lastName = String(recipient.@lastName);

    logInfo(
      "ID: " + id +
      ", email: " + email +
      ", last name: " + lastName
    );
  }
}

Before using a query in a production workflow, confirm that:

  • The schema is correct.
  • Each `node` expression resolves to the intended attribute.
  • The `where` condition returns the intended records.
  • The returned XML contains the expected nodes.
  • The script handles an empty result.

Use Session Methods Only for Explicit Record Changes

The same data-oriented API family includes Campaign session methods for writing schema records. Keep record changes separate from the selection that identifies the records: query the intended records first, then apply a write operation only to the specific schema records the script is designed to change.

var testRecipientId = 123456;

var recipientQuery = xtk.queryDef.create(
  <queryDef schema="nms:recipient" operation="getIfExists">
    <select>
      <node expr="@id"/>
      <node expr="@lastName"/>
    </select>
    <where>
      <condition expr={"@id = " + testRecipientId}/>
    </where>
  </queryDef>
);

var recipient = recipientQuery.ExecuteQuery();

if (String(recipient.@id) === "") {
  logInfo("The test recipient was not found.");
} else {
  xtk.session.Write(
    <recipient
      xtkschema="nms:recipient"
      _operation="update"
      _key="@id"
      id={String(recipient.@id)}
      lastName="Smith"
    />
  );
}

Test write logic against a restricted set of records before using it in a production workflow. Confirm the target schema, record identifier, and values to be written before executing a change.

Apply queryDef in an A/B Test Script

The A/B testing JavaScript use case shows a workflow script retrieving delivery information, comparing results, and using that decision in the workflow’s A/B test process.

var deliveryAId = 123456;
var deliveryBId = 123457;

var deliveryQuery = xtk.queryDef.create(
  <queryDef schema="nms:delivery" operation="select" lineCount="2">
    <select>
      <node expr="@id"/>
      <node expr="@label"/>
      <node
        expr="[indicators/@estimatedRecipientOpenRatio]"
        alias="@openRate"
      />
    </select>
    <where>
      <condition
        expr={"@id = " + deliveryAId + " OR @id = " + deliveryBId}
      />
    </where>
    <orderBy>
      <node
        expr="[indicators/@estimatedRecipientOpenRatio]"
        sortDesc="true"
      />
    </orderBy>
  </queryDef>
);

var deliveries = deliveryQuery.ExecuteQuery().delivery;

// Clear any value left by an earlier execution.
vars.winningTestDeliveryId = 0;

if (deliveries.length() !== 2) {
  logInfo("Both test deliveries must exist before comparison.");
} else {
  var first = deliveries[0];
  var second = deliveries[1];

  var firstRateText = String(first.@openRate);
  var secondRateText = String(second.@openRate);
  var firstRate = Number(firstRateText);
  var secondRate = Number(secondRateText);

  if (
    firstRateText === "" || secondRateText === "" ||
    !isFinite(firstRate) || !isFinite(secondRate) ||
    firstRate < 0 || secondRate < 0
  ) {
    logInfo("The test deliveries do not have usable open rates.");
  } else if (firstRate === secondRate) {
    logInfo("The open rates are equal. No winner was selected.");
  } else {
    vars.winningTestDeliveryId = Number(first.@id);

    logInfo(
      "Winning test delivery: " + String(first.@label) +
      ", estimated open rate: " + firstRate
    );
  }
}

Note: This script uses Adobe Campaign Classic’s E4X support for XML syntax, .@ attribute access, and XML collection methods such as length(). String(), Number(), and isFinite() are standard ES3 functions.

The query retrieves the values needed for the decision. The JavaScript defines the comparison logic and must account for an empty or unusable result before it selects a delivery version.

Keep the query limited to the delivery attributes and result values used by the comparison. This makes the decision logic easier to review and avoids coupling the script to unrelated data.

Oh hi there đź‘‹
I have a SSJS skill for you.

Sign up now to get an SSJS skill that can be used with your AI companion

We don’t spam! Read our privacy policy for more info.

Share With Others

The Author
Marcel Szimonisz Platinum

Marcel Szimonisz

MarTech consultant

I specialize in solving problems, automating processes, and driving innovation through major marketing automation platforms, particularly Salesforce Marketing Cloud and Adobe Campaign.

Your email address will not be published. Required fields are marked *

Get exclusive tips, scripts and news

Choose your topics

We don’t spam! Read our privacy policy for more info.

Similar posts
Add to this article

Share your experience

Your contribution

We will review your contribution and may include it in the article, with your name if you choose.

Article history

What changed