【问题标题】:Deduping results returned by a Mongo aggregate queryMongo 聚合查询返回的重复数据删除结果
【发布时间】:2016-10-28 15:45:58
【问题描述】:

一些背景:

这涉及 3 个集合:

  1. 帖子
  2. 帖子子类别
  3. 后超类别


帖子中的文档示例:

{
    "_id" : ObjectId("57fbf3ce7ccbc906ed87cef6"),
    "__v" : 6,
    "author" : ObjectId("57fbe2ac3cfb9e061df86ebb"),
    "postSubCategories" : [ 
        ObjectId("5806344baa0bbf284a2316e4")//reference to document in postsubcategories collection
    ],
    "postSuperCategories" : [ 
        ObjectId("580679958a5f5f448ba5aae9"), 
        ObjectId("580679958a5f5f448ba5aaf2")//references to documents in postsupercategories collection
    ],
    "publishedDate" : ISODate("2016-10-10T04:00:00.000Z"),
    "state" : "published",
    "templateName" : ObjectId("57fbf3977ccbc906ed87cef3"),
    "title" : "My title",
    "topics" : []}

我的查询是

db.posts.aggregate([
{'$unwind': 
    {'path':"$postSubCategories"}
},
{'$lookup': {
  'from':"postsubcategories",
  'localField': "postSubCategories",
  'foreignField': "_id",
  'as': "subObject"
}},
{'$unwind': 
    {'path':"$postSuperCategories"}
},
{'$lookup': {
  'from':"postsupercategories",
  'localField': "postSuperCategories",
  'foreignField': "_id",
  'as': "superObject"
}},
{'$match': {
    '$or':
        [{ "subObject.searchKeywords": "home monitor" }, 
        { "superObject.searchKeywords": "home monitor" }]
    }
},
{'$match': {
    "state": "published"
}}


postsubcategories 和 postsupercategories 集合都包含一个名为 searchKeywords 的字段,该字段是其文档中的文本数组。我希望能够查询那些 searchKeywords 字段并返回匹配的帖子文档。我需要一组经过重复数据处理的返回 _id。

该查询返回四个文档。示例:

ObjectId("57fbf3ce7ccbc906ed87cef6")
ObjectId("57fbf3ce7ccbc906ed87cef6")
ObjectId("57fbf40b7ccbc906ed87cef7")
ObjectId("57fbf40b7ccbc906ed87cef7") 


我明白它为什么返回 4。一个文档包含 postSubCategories 对象 5806344baa0bbf284a2316e4 和 postSuperCategories id 580679958a5f5f448ba5aae9

第二个文档包含 postSubCategories 对象 5806344baa0bbf284a2316e4 和 postSuperCategories 580679958a5f5f448ba5aaf2。第二个帖子重复此操作

有没有一种方法可以根据返回的 _id 进行“重复数据删除”?

我的最终结果是:
ObjectId("57fbf3ce7ccbc906ed87cef6")
ObjectId("57fbf40b7ccbc906ed87cef7")

我知道从技术上讲,4 个列表中的 2 个匹配的 _id 并不完全相同,因为它们每个都包含不同的 postSuperCategories 对象,但此时我不再关心该字段,只需要一个单一的帖子文档因为我需要访问其他字段。

任何帮助将不胜感激。我曾尝试调查$group$addToSet$setUnion,但到目前为止都没有成功。

【问题讨论】:

    标签: mongodb mongoose mongodb-query aggregation-framework mongodb-aggregation


    【解决方案1】:

    您可以添加一个$group 检索不同的_id,并为每个_id 要提取的每个属性找到第一个值。

    对于$group 聚合:

    {
        '$group': {
            _id: '$_id',
            item: { $first: "$$ROOT" } 
        }
    }
    

    这将在item 字段中为您提供root document 的第一项:

    { "_id" : ObjectId("57fbf40b7ccbc906ed87cef7"), "items" : { "_id" : ObjectId("57fbf40b7ccbc906ed87cef7"), "__v" : 6, "author" : ObjectId("57fbe2ac3cfb9e061df86ebb"), "postSubCategories" : ObjectId("5806344baa0bbf284a2316e4"), "postSuperCategories" : ObjectId("580679958a5f5f448ba5aae9"), "publishedDate" : ISODate("2016-12-10T04:00:00Z"), "state" : "published", "templateName" : ObjectId("57fbf3977ccbc906ed87cef4"), "title" : "My title2", "topics" : [ "a", "b" ], "subObject" : [ { "_id" : ObjectId("5806344baa0bbf284a2316e4"), "searchKeywords" : "home monitor" } ], "superObject" : [ { "_id" : ObjectId("580679958a5f5f448ba5aae9"), "searchKeywords" : "home monitor2" } ] } }
    { "_id" : ObjectId("57fbf3ce7ccbc906ed87cef6"), "items" : { "_id" : ObjectId("57fbf3ce7ccbc906ed87cef6"), "__v" : 6, "author" : ObjectId("57fbe2ac3cfb9e061df86ebb"), "postSubCategories" : ObjectId("5806344baa0bbf284a2316e4"), "postSuperCategories" : ObjectId("580679958a5f5f448ba5aae9"), "publishedDate" : ISODate("2016-10-10T04:00:00Z"), "state" : "published", "templateName" : ObjectId("57fbf3977ccbc906ed87cef3"), "title" : "My title", "topics" : [ ], "subObject" : [ { "_id" : ObjectId("5806344baa0bbf284a2316e4"), "searchKeywords" : "home monitor" } ], "superObject" : [ { "_id" : ObjectId("580679958a5f5f448ba5aae9"), "searchKeywords" : "home monitor2" } ] } }
    

    否则,在响应中选择一个字段:

    {
        '$group': {
            _id: '$_id',
            author: {
                $first: '$author'
            },
            publishedDate: {
                $first: '$publishedDate'
            },
            state: {
                $first: '$state'
            },
            templateName: {
                $first: '$templateName'
            },
            title: {
                $first: '$title'
            },
            topics: {
                $first: '$topics'
            }
        }
    }
    

    你会得到类似的东西:

    { "_id" : ObjectId("57fbf40b7ccbc906ed87cef7"), "author" : ObjectId("57fbe2ac3cfb9e061df86ebb"), "publishedDate" : ISODate("2016-10-10T04:00:00Z"), "state" : "published", "templateName" : ObjectId("57fbf3977ccbc906ed87cef3"), "title" : "My title", "topics" : [ ] }
    { "_id" : ObjectId("57fbf3ce7ccbc906ed87cef6"), "author" : ObjectId("57fbe2ac3cfb9e061df86ebb"), "publishedDate" : ISODate("2016-10-10T04:00:00Z"), "state" : "published", "templateName" : ObjectId("57fbf3977ccbc906ed87cef3"), "title" : "My title", "topics" : [ ] }
    

    【讨论】:

    • 谢谢!我开始走这条路,但不太明白。我对这样做的最大担忧是,如果添加了我想要返回的新字段,它不会给我留下太多的灵活性。我将不得不进入代码并不断更新此查询而不是所有字段,包括自动返回的任何潜在的新字段。
    • 我编辑了我的帖子,使用$first: "$$ROOT" 获取上一个文档
    • 啊!才发现这个。这看起来是最好的选择。感谢您的帮助
    猜你喜欢
    • 2016-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-14
    • 1970-01-01
    • 2011-12-09
    • 2017-07-02
    • 2021-02-03
    相关资源
    最近更新 更多