这三个中最容易使用聚合的是交集**。一般情况可以使用聚合来完成,如下所示:
路口:
db.colors.aggregate([
{'$unwind' : "$left"},
{'$unwind' : "$right"},
{'$project': {
value:"$left",
same:{$cond:[{$eq:["$left","$right"]}, 1, 0]}
}
},
{'$group' : {
_id: {id:'$_id', val:'$value'},
doesMatch:{$max:"$same"}
}
},
{'$match' :{doesMatch:1}},
]);
另外两个变得有点棘手。据我所知,没有办法将同一文档中的两个单独字段组合在一起。在 $project 管道阶段有一个 $add、$combine 或 $addToSet 会很好,但是这不存在。因此,我们能做的最好的事情就是说出某物是否相交。我们可以从以下两个聚合开始:
db.colors.aggregate([
{'$unwind' : "$left"},
{'$unwind' : "$right"},
{'$project': {
left:"$left",
right:'$right',
same:{$cond:[{$eq:["$left","$right"]}, 1, 0]}
}
},
{'$group' : {
_id:{id:'$_id', left:'$left'},
right:{'$addToSet':'$right'},
sum: {'$sum':'$same'},
}
},
{'$project': {
left:{val:"$_id.left",inter:"$sum"},
right:'$right',
}
},
{'$unwind' : "$right"},
{'$project': {
left:"$left",
right:'$right',
same:{$cond:[{$eq:["$left.val","$right"]}, 1, 0]}
}
},
{'$group' : {
_id:{id:'$_id.id', right:'$right'},
left:{'$addToSet':'$left'},
sum: {'$sum':'$same'},
}
},
{'$project': {
right:{val:"$_id.right",inter:"$sum"},
left:'$left',
}
},
{'$unwind' : "$left"},
{'$group' : {
_id:'$_id.id',
left:{'$addToSet':'$left'},
right: {'$addToSet':'$right'},
}
},
]);
问题中提供的样本的这种聚合将给出如下结果:
{
"_id" : 1,
"left" : [
{
"val" : "green",
"inter" : 1
},
{
"val" : "red",
"inter" : 0
}
],
"right" : [
{
"val" : "blue",
"inter" : 0
},
{
"val" : "green",
"inter" : 1
}
]
}
从这里我们可以通过将以下内容添加到聚合中来获得交集:
{'$project': {
left:"$left"
}
},
{'$unwind' : "$left"},
{'$match' : {'left.inter': 1}},
{'$group' : {
_id:'$_id',
left:{'$addToSet':'$left'},
}
},
我们可以通过将以下内容添加到基本聚合的末尾来找到差异以及相对补充:
{'$unwind' : "$left"},
{'$match' : {'left.inter': 0}},
{'$unwind' : "$right"},
{'$match' : {'right.inter': 0}},
{'$group' : {
_id:'$_id',
left:{'$addToSet':'$left'},
right:{'$addToSet':'$right'},
}
},
不幸的是,似乎没有一种将来自不同领域的不同项目组合在一起的好方法。为了获得工会,似乎最好从客户那里做到这一点。或者,如果您想要过滤,请分别对每个集合进行过滤。