【问题标题】:How to find a set of documents by specific field(s) of similar value in mongoose / mongodb?如何通过 mongoose / mongodb 中具有相似值的特定字段查找一组文档?
【发布时间】:2014-12-23 03:14:50
【问题描述】:

我想看看一个集合中是否有一些重复的文档,以便我可以删除或合并相似的记录。

假设没有提供目标值,只提供目标字段,我所要做的就是根据目标字段找到所有相似的文档。

例如,我的集合persons 包含以下文档:

{
    _id: 1,
    email: "foo@bar.com",
    name: "tom",
    phone: 320513218,
    company: {
        name: "Bar"
        department: "Marketing"
    }
},{
    _id: 2,
    email: "foo@bar.com",
    name: "alex c",
    phone: 7320320813,
    company: {
        name: "Bar"
        department: "Development"
    }
},{
    _id: 3,
    email: "not_foo@not_bar.com",
    name: "alex w",
    phone: 895120981,
    company: {
        name: "Not Bar"
        department: "Development"
    }
},{
    _id: 4,
    email: "not_foo@not_bar.com",
    name: "emily",
    phone: 895120981,
    company: {
        name: "Another Company"
        department: "Marketing"
    }
},{
    _id: 5,
    email: "foo@bar.com",
    name: "emily",
    phone: 7320320813,
    company: {
        name: "Another Company"
        department: "Marketing"
    }
},...
  1. 我想先找到基于email的重复文档,我应该得到[{_id: 1, count: 3}, {_id: 2, count: 3}, {_id: 5, count: 3}, {_id: 3, count: 2}, {_id: 4, count: 2}]作为结果。 (不用担心数组的顺序)

  2. 然后,我想根据phone查找重复文档,结果应该是[{_id: 2, count: 2}, {_id: 5, count: 2}, {_id: 3, count: 2}, {_id: 4, count: 2}]。 (不用担心数组的顺序)

  3. 那么,我想根据name查找重复文档,结果应该是[{_id: 2, count: 2}, {_id: 3, count: 2}, {_id: 4, count: 2}, {_id: 5, count: 2}]

  4. 最后,我想根据emailphone找到重复的文档,结果应该是[{_id: 2, count: 2}, {_id: 5, count: 2}]

count应该是重复记录的数量(自包含))

我已经尝试了 mongo/mongoose 提供的 mapReduceaggregate 方法,但它们无法满足我的期望。

我想要“按多个(相似)字段分组和计数”之类的东西

如果您需要更多信息,请告诉我,例如我当前的示例代码。

【问题讨论】:

    标签: node.js mongodb mongoose


    【解决方案1】:

    您需要为每个重复搜索单独聚合。在所有情况下,只需对定义重复项的(可能是复合的)键进行分组,然后将 _id 推送到数组并计算结果数:

    db.test.aggregate([
        { "$group" : { "_id" : KEY, "ids" : { "$push" : "$_id" }, "count" : { "$sum" : 1 } } }
    ])
    

    例如,对于phone

    db.test.aggregate([
        { "$group" : { "_id" : "$phone", "ids" : { "$push" : "$_id" }, "count" : { "$sum" : 1 } } }
    ])
    

    对于emailphone

    db.test.aggregate([
        { "$group" : { "_id" : { "phone" : "$phone", "email" : "$email" }, "ids" : { "$push" : "$_id" }, "count" : { "$sum" : 1 } } }
    ])
    

    这会提供与您所要求的不同的输出,例如您的示例文档和phone 您得到的输出

    { "_id" : 895120981, "ids" : [3, 4], "count" : 2 },
    { "_id" : 7320320813, "ids" : [2, 5], "count" : 2 },
    { "_id" : 320513218, "ids" : [1], "count" : 1 }
    

    但它具有相同的信息,并且是更简单(更快)的聚合。

    要过滤掉唯一值,请附加 $match 阶段:

    { "$match" : { "count" : { "$gt" : 1 } } }
    

    【讨论】:

    • 感谢您的建议。我认为它可能适用于完全相同的值,但我可以按特定字段的相似值分组吗?比如{_id: 2}, {_id: 3},它们都被命名为alex,但不同的中间名或姓氏。
    【解决方案2】:

    问题 1 的解决方案。

    db.test.aggregate(
    { $group: 
            { _id : 
                {email : '$email'},  
                    id : {$push :"$_id"},
                    count : {$sum:1}        
            }
    },
    {$unwind:"$id"},
    {$group: 
            {_id: 
                {_id:"$id",count:"$count"},
    
                }
         }
    )
    

    【讨论】:

    • 为什么需要第二个$group
    • 我实际上想对输出进行切片以仅获取 _id 和计数。不知何故无法切片,因此使用了组。
    猜你喜欢
    • 1970-01-01
    • 2021-09-30
    • 2016-06-18
    • 2019-10-11
    • 1970-01-01
    • 1970-01-01
    • 2011-08-11
    • 2015-02-13
    相关资源
    最近更新 更多