使用数组字段的元素对mongo文档进行分组

时间:2016-10-09 20:06:54

标签: mongodb mapreduce aggregation-framework

我有3个以下的文件。每个代表用户的联系人:

{ 
    "_id" : ObjectId("57f9f9f3b91d070315273d0d"), 
    "profileId" : "test", 
    "displayName" : "duplicateTest", 
    "email" : [
        {
            "emailId" : "a@a.com"
        }, 
        {
            "emailId" : "b@b.com"
        }, 
        {
            "emailId" : "c@c.com"
        }
    ]
}
{ 
    "_id" : ObjectId("57f9fab2b91d070315273d11"), 
    "profileId" : "test", 
    "displayName" : "duplicateTest2", 
    "email" : [
        {
            "emailId" : "a@a.com"
        }
    ]
}
{ 
    "_id" : ObjectId("57f9fcefb91d070315273d15"), 
    "profileId" : "test", 
    "displayName" : "duplicateTest2", 
    "email" : [
        {
            "emailId" : "b@b.com"
        }
    ]
}

我需要按数组元素聚合/分组它们,以便我可以识别重复的联系人(基于电子邮件ID)。由于doc(1& 2)和doc(1& 3)之间有一个共同的电子邮件ID,因此这3个代表一个联系人,应该作为一个联系人合并为一个。

我尝试使用$ unwind和java中的$ group执行此操作,如下所示:

List<DBObject> aggList = new ArrayList<DBObject>();

        BasicDBObject dbo = new BasicDBObject("$match", new BasicDBObject("profileId", "0fb72dcf-292b-4343-a0e7-1d613a803b1e"));

        aggList.add(dbo);

        BasicDBObject dboUnwind = new BasicDBObject("$unwind", "$email");
        aggList.add(dboUnwind);



        BasicDBObject dboGroup = new BasicDBObject("$group",
                new BasicDBObject().append("_id", new BasicDBObject("name", "$email.emailId"))
                        .append("uniqueIds", new BasicDBObject("$addToSet", "$_id"))
                        .append("count", new BasicDBObject("$sum", 1)));

        aggList.add(dboGroup);

        BasicDBObject dboCount = new BasicDBObject("$match", new BasicDBObject("count", new BasicDBObject("$gte", 2)));
        aggList.add(dboCount);


        BasicDBObject dboSort = new BasicDBObject("$sort", new BasicDBObject("count",-1));
        aggList.add(dboSort);


        BasicDBObject dboLimit = new BasicDBObject("$limit", 10);
        aggList.add(dboLimit);


        AggregationOutput output = collection.aggregate(aggList);


    System.out.println(output.results());

这通过电子邮件ID对文档进行分组(这是正确的),但不能达到目的。

任何帮助都将受到高度赞赏。

我需要实现一个功能,可以提示用户有关其存储库中可能存在的重复联系人的信息。我需要聚合结果:

[  
   {  
      "_id":{  
         "name":[  
            {
            "emailId" : "a@a.com"
        }, 
        {
            "emailId" : "b@b.com"
        }, 
        {
            "emailId" : "c@c.com"
        }
         ]
      },
      "uniqueIds":[  
         {  
            "$oid":"57f9fcefb91d070315273d15"
         },
 {  
            "$oid":"57f9fcefb91d070315273d11"
         },
 {  
            "$oid":"57f9fcefb91d070315273d15"
         }
      ],
      "count":3
   },

所以基本上,我需要_id用于所有可能的重复联系人(可能有另一组带有_ids列表的重复项),以便我可以提示用户和用户可以按照他的意愿合并它们。 希望现在更清楚。谢谢!

1 个答案:

答案 0 :(得分:0)

那么你的问题与你所寻求的结果略有不同。您的初始问题向我指出了以下聚合:

db.table.aggregate(
  [
    {
      $unwind: "$email"
    },
    {
      $group: {
      _id : "$email.emailId",
      duplicates : { $addToSet : "$_id"}
      }
    }
  ]
);

这导致:

{ 
    "_id" : "c@c.com", 
    "duplicates" : [
        ObjectId("57f9f9f3b91d070315273d0d")
    ]
}
{ 
    "_id" : "b@b.com", 
    "duplicates" : [
        ObjectId("57f9fcefb91d070315273d15"), 
        ObjectId("57f9f9f3b91d070315273d0d")
    ]
}
{ 
    "_id" : "a@a.com", 
    "duplicates" : [
        ObjectId("57f9fab2b91d070315273d11"), 
        ObjectId("57f9f9f3b91d070315273d0d")
    ]
}

由电子邮件分组。

但是您添加到问题中的示例输出进行了此聚合:

db.table.aggregate(
  [
    {
      $unwind: "$email"
    },
    {
      $group: {
      _id : "$profileId",
      emails : { $addToSet : "$email.emailId"},
      duplicates : { $addToSet : "$_id"}
      }
    }
  ]
);

结果是:

{ 
    "_id" : "test", 
    "emails" : [
        "c@c.com", 
        "b@b.com", 
        "a@a.com"
    ], 
    "duplicates" : [
        ObjectId("57f9fcefb91d070315273d15"), 
        ObjectId("57f9fab2b91d070315273d11"), 
        ObjectId("57f9f9f3b91d070315273d0d")
    ]
}