我有一个要求,需要对两条记录进行聚合,这两条记录都有一个值不同的数组字段.我需要的是,当我对这些记录进行聚合时,结果应该有一个数组,其中包含来自两个不同数组的唯一值.下面是一个例子:

第一张唱片

 { Host:"abc.com" ArtId:"123", tags:[ "tag1", "tag2" ] }

第二记录

{ Host:"abc.com" ArtId:"123", tags:[ "tag2", "tag3" ] }

在主机和artid上聚合后,我需要这样的结果:

 { Host: "abc.com", ArtId: "123", count :"2", tags:[ "tag1", "tag2", "tag3" ]}

我试着在团体声明中加入$addToset个,但它给出了这样的标签:[["tag1","tag2"],["tag2","tag3"]]

你能帮我怎样才能做到这一点吗

推荐答案

太长,读不下go 了

现代版本应在最初的$group之后使用$reduce$setUnion,如图所示:

db.collection.aggregate([
  { "$group": {
    "_id": { "Host": "$Host", "ArtId": "$ArtId" },
    "count": { "$sum": 1 },
    "tags": { "$addToSet": "$tags" }
  }},
  { "$addFields": {
    "tags": {
      "$reduce": {
        "input": "$tags",
        "initialValue": [],
        "in": { "$setUnion": [ "$$value", "$$this" ] }
      }
    }
  }}
])

您找到$addToSet运算符是对的,但在处理数组中的内容时,通常需要先处理$unwind运算符.这会"反规范化"数组条目,并基本上生成父文档的"副本",每个数组条目在字段中都是单数值.这就是你在不使用它的情况下避免看到的行为所需要的.

虽然"计数"带来了一个有趣的问题,但在最初的$group次操作后,通过使用"双重放松"很容易解决:

db.collection.aggregate([
    // Group on the compound key and get the occurrences first
    { "$group": {
        "_id": { "Host": "$Host", "ArtId": "$ArtId" },
        "tcount": { "$sum": 1 },
        "ttags": { "$push": "$tags" }
    }},

    // Unwind twice because "ttags" is now an array of arrays
    { "$unwind": "$ttags" },
    { "$unwind": "$ttags" },

    // Now use $addToSet to get the distinct values        
    { "$group": {
        "_id": "$_id",
        "tcount": { "$first": "$tcount" },
        "tags": { "$addToSet": "$ttags" }
    }},

    // Optionally $project to get the fields out of the _id key
    { "$project": {
        "_id": 0,
        "Host": "$_id.Host",
        "ArtId": "$_id.ArtId",
        "count": "$tcount",
        "tags": "$ttags"
    }}
])

最后一位是$project,因为我在聚合管道的其他阶段 for each 字段使用了"临时"名称.这是因为在$project中有一个优化,即在将任何"新"字段添加到文档之前,按照字段已经出现的顺序"复制"现有阶段中的字段.

否则,输出将如下所示:

{  "count":2 , "tags":[ "tag1", "tag2", "tag3" ], "Host": "abc.com", "ArtId": "123" }

字段的顺序与您可能认为的不同.这真的很琐碎,但对一些人来说很重要,所以值得解释为什么,以及如何处理.

因此,$unwind的作用是保持项目分开,而不是在数组中,而首先执行$group可以获得"分组"键出现的"计数".

后来使用的$first运算符"保留"了"count"值,因为它只是对"tags"数组中的每个值进行了"复制".反正都是一样的,所以没关系.随便挑一个.

Mongodb相关问答推荐

在mongdob中按子文档筛选不起作用

将子元素的数组值提取到 mongodb 中的单个数组中?

从MongoDB迁移到PostgreSQL:为PostgreSQL编写聚合管道查询

通过insertId MongoDB获取文档

是否可以迭代 mongo 游标两次?

如何构建我只需要打开一次 mongodb 连接的快速应用程序?

使用模拟 MongoDB 服务器进行单元测试

在 MongoDB 中创建简短、唯一的对象 ID

删除嵌套文档数组中的嵌入文档

MongoDB - 清除嵌套数组中的元素

不能在模块外使用 import 语句

启动mongodb和express的正确方法?

如何返回 MongoDB 中文档的 ObjectId 或 _id?和错误$in 需要一个数组

MongoDB - 我如何找到另一个集合中的文档未引用的所有文档

mongodb 的计数性能

MongoDB如何判断是否存在

如何匹配 MongoDB 聚合框架中的 undefined值?

MongoDB 按数组元素对文档进行排序

如何使用 mongoose 连接到 mongoDB Atlas

如何从集合中删除除 MongoDB 中的文档之外的所有文档