Самый простой из этих трех с использованием агрегации является пересечением **. Общий случай для этого может быть сделано с помощью агрегации так:
Пересечения:
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}},
]);
два других становятся немного сложнее. Насколько я знаю, нет единого способа объединить два отдельных поля в одном документе. Было бы неплохо иметь $ add, $ comb или $ addToSet в фазе проекта $ project, но этого не существует. Поэтому лучшее, что мы можем сделать, это сказать, что что-то пересекло или нет. Мы можем начать как агрегирование с нижеследующим:
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'},
}
},
К сожалению, как представляется, не является хорошим способом объединить разнородные элементы из различных областей вместе. Чтобы получить союз, лучше всего сделать это от клиента. Или, если вы хотите фильтровать, делайте это по каждому набору отдельно.
Этот вопрос был вдохновлен этим [ответом] (http://stackoverflow.com/a/17266323/311525). Я нашел несколько конкретных случаев, но не общие случаи, которые я искал. – Scott
Возможный дубликат [Использовать агрегацию MongoDB для поиска множества пересечений двух наборов в одном документе] (http://stackoverflow.com/questions/17264017/use-mongodb-aggregation-to-find-set-intersection-of-two -sets-in-the-same-doc) – WiredPrairie
@WiredPrairie, учитывая, что тот, с которым вы связаны, является моим, я могу заверить вас, что они не дублируют вопросы. Тот, с которым вы связаны, является очень конкретным случаем, когда найдено подмножество. Это более общий более общий вопрос о пересечении, союзах и различиях. – Scott