MongoDB - 计算几个数组的唯一值

时间:2013-12-22 17:59:39

标签: mongodb aggregation-framework

我正在尝试找到一种方法来在同一文档和文档中获取多个数组的唯一值。最好用一个例子来解释:

[
    {
      _id: "x",
      products: {
        product_a: ["v1", "v2"],
        product_b: ["v3", "v2"]
      }
    },
    {
      _id: "y",
      products: {
        product_a: ["v1"],
        product_b: ["v3", "v4"]
      }
    }
]

我想要的是:

  1. 每个文档的唯一值数。有3个独特的 'x'中的产品值和'y'中的3个唯一值。
  2. 数量 整体的独特价值。所有文档都有4个唯一值 在集合中。

1 个答案:

答案 0 :(得分:2)

当您无法或不愿意更改架构时,您可以同时使用MapReduce

每个文档的唯一值

您的map-function会将产品中的所有数组连接成一个,删除重复项,然后以_id为键发出该数组的大小。有关如何删除重复项的详细信息可以在this question中找到(忽略使用库浏览器javascript的答案)。

function mapFunction() {
    var ret = [];
    for (var product in this.products) {
        for (var i = 0; i < product.length; i++) {
            ret.push(product[i]);
        }
    }

    [ remove duplicates with your favorite method from question 9229645 ]

    return ret.length;
}

您的密钥是唯一的,因此每个密钥永远不会调用您的reduce函数。这意味着它只能返回values-array的第一个元素。

function reduceFunction(key, values) {
    return values[0];
}

总体上的唯一值

您可以通过将每个值作为键发送但具有无意义的值来实现此目的。

您的map-function将迭代products-object,然后迭代数组

 function mapFunction() {
      for (var product in this.products) {
          for (var i = 0; i < product.length; i++) {
              emit(product[i], null);
          }
      }
 }

因为这些值没有意义,所以你的reduce函数对它们没有任何作用:

function reduceFunction(key, values) {
    return null;
}

结果将是一组文档,其中每个_id是数据中唯一的值之一。

何时可以更改架构

如果没有充分的理由让您的架构保持现状,那么将products对象转换为数组可以让您的生活更轻松:

  products: [
    { product: "product_a", values: ["v1", "v2"] },
    { product: "product_b", values: ["v3", "v2"] }
  ]

在这种情况下,您可以使用聚合管道。

  1. 使用$unwind将值数组转换为唯一文档
  2. 使用$group$addToSet重新合并文档,同时放弃文档
  3. 再次使用$ unwind来获取一系列独特文档,但这次没有重复文件
  4. 使用$ $sum:1来计算唯一值。