如何在mongoose / mongodb中按类似值的特定字段查找一组文档?

时间:2014-12-22 10:05:21

标签: node.js mongodb mongoose

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

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

例如,我的集合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}]作为结果。

  5. count应该是重复记录的数量(包括在内))

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

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

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

2 个答案:

答案 0 :(得分: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 } } }

答案 1 :(得分:0)

问题1的解决方案。

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

            }
     }
)