static getUnique (req, res) {
    ArkimeUtil.noCache(req, res, 'text/plain; charset=utf-8');

    // req.query.exp -> req.query.field by viewer.js:expToField

    if (!ArkimeUtil.isString(req.query.field)) {
      return res.send('Missing field or exp parameter');
    }

    /* How should the results be written.  Use setImmediate to not blow stack frame */
    let writeCb;
    let doneCb;
    const items = [];
    let aggSize = +Config.get('maxAggSize', 10000);

    if (req.query.autocomplete !== undefined) {
      if (!Config.get('valueAutoComplete', !Config.get('multiES', false))) {
        res.send([]);
        return;
      }

      const spiDataMaxIndices = +Config.get('spiDataMaxIndices', 4);
      if (spiDataMaxIndices !== -1) {
        if (req.query.date === '-1' ||
            (req.query.date !== undefined && +req.query.date > spiDataMaxIndices)) {
          console.log(`INFO For autocomplete replacing date=${ArkimeUtil.safeStr(req.query.date)} with ${spiDataMaxIndices}`);
          req.query.date = spiDataMaxIndices;
        }
      }

      aggSize = 1000; // lower agg size for autocomplete
      doneCb = () => {
        res.send(items);
      };

      writeCb = (item) => {
        items.push(item.key);
      };
    } else if (parseInt(req.query.counts, 10) || 0) {
      writeCb = (item) => {
        res.write(`${item.key}, ${item.doc_count}\n`);
      };
    } else {
      writeCb = (item) => {
        res.write(`${item.key}\n`);
      };
    }

    /* How should each item be processed. */
    let eachCb = writeCb;

    if (req.query.field.match(/(ip.src:port.src|a1:p1|srcIp:srtPort|ip.src:srcPort|ip.dst:port.dst|a2:p2|dstIp:dstPort|ip.dst:dstPort|source.ip:source.port|ip.src:source.port|ip.dst:destination.port)/)) {
      eachCb = (item) => {
        const sep = (item.key.indexOf(':') === -1) ? ':' : '.';
        item.field2.buckets.forEach((item2) => {
          item2.key = item.key + sep + item2.key;
          writeCb(item2);
        });
      };
    }

    SessionAPIs.buildSessionQuery(req, (err, query, indices) => {
      if (err) {
        res.status(403);

        return res.send(err.toString());
      }

      const fieldDef = Config.getFieldsMap()[req.query.field];
      if (req.query.autocomplete !== undefined && fieldDef && fieldDef.type === 'integer') {
        query.query.bool.filter.push({
          script: {
            script: {
              source: `doc["${req.query.field}"].size() > 0 && doc["${req.query.field}"].value.toString().startsWith("${req.query.autocomplete}")`
            }
          }
        });
      }

      delete query.sort;
      delete query.aggregations;

      if (req.query.field.match(/(ip.src:port.src|a1:p1|srcIp:srcPort|ip.src:srcPort|source.ip:source.port|ip.src:source.port)/)) {
        query.aggregations = { field: { terms: { field: 'source.ip', size: aggSize }, aggregations: { field2: { terms: { field: 'source.port', size: 100 } } } } };
      } else if (req.query.field.match(/(ip.dst:port.dst|a2:p2|dstIp:dstPort|ip.dst:dstPort|destination.ip:destination.port|ip.dst:destination.port)/)) {
        query.aggregations = { field: { terms: { field: 'destination.ip', size: aggSize }, aggregations: { field2: { terms: { field: 'destination.port', size: 100 } } } } };
      } else if (req.query.field === 'fileand') {
        query.aggregations = { field: { terms: { field: 'node', size: aggSize }, aggregations: { field2: { terms: { field: 'fileId', size: 100 } } } } };
      } else {
        query.aggregations = { field: { terms: { field: req.query.field, size: aggSize } } };
      }

      query.size = 0;
      console.log('/api/unique aggregations', indices, JSON.stringify(query));

      function findFileNames (result) {
        const intermediateResults = [];
        const aggs = result.aggregations.field.buckets;
        aggs.forEach((item) => {
          item.field2.buckets.forEach((sitem) => {
            intermediateResults.push({ key: item.key + ':' + sitem.key, doc_count: sitem.doc_count });
          });
        });

        async.each(intermediateResults, async (fsitem) => {
          const split = fsitem.key.split(':');
          const node = split[0];
          const fileId = split[1];
          try {
            const file = await Db.fileIdToFile(node, fileId);
            if (file && file.name) {
              eachCb({ key: file.name, doc_count: fsitem.doc_count });
            }
          } catch (err) {
            // Ignore error
          }
        }, () => {
          return res.end();
        });
      }

      const options = ViewerUtils.addCluster(req.query.cluster);
      Db.searchSessions(indices, query, options, (err, result) => {
        if (err) {
          console.log(`ERROR - ${req.method} /api/unique`, query, util.inspect(err, false, 50));
          return doneCb ? doneCb() : res.end();
        }
        if (Config.debug) {
          console.log('/api/unique result', util.inspect(result, false, 50));
        }
        if (!result.aggregations || !result.aggregations.field) {
          return doneCb ? doneCb() : res.end();
        }

        if (req.query.field === 'fileand') {
          return findFileNames(result);
        }

        const ilen = result.aggregations.field.buckets.length;
        for (let i = 0; i < ilen; i++) {
          eachCb(result.aggregations.field.buckets[i]);
        }

        return doneCb ? doneCb() : res.end();
      });
    });
  }
POST/GET - /api/unique

Builds an elasticsearch session query. Gets a list of unique field values (with or without counts) and sends them to the client.
@name /unique
@param {SessionsQuery} See_List - This API supports a common set of parameters documented in the SessionsQuery section
@param {number} counts=0 - Whether to return counts with he list of unique field values. Defaults to 0. 0 = no counts, 1 - counts.
@param {string} exp - The expression field to return unique data for. Either exp or field is required, field is given priority if both are present.
@param {string} field - The database field to return unique data for. Either exp or field is required, field is given priority if both are present.
@returns {string} The list of unique fields (with counts if requested)