我尝试了类似下面的内容,但是dint得到了预期的结果,如果字段不是数组,这应该有效
// union of includes and excludes as excludesAndExcludes
getIncludesAndExcludes: (req, res)=>{
console.log('called setunion');
experienceModel.aggregate([
{ $group: {_id : {includes:"$includes", excludes:"$excludes"}}},
{ $project: { includesAndExcludes: { $setUnion: [ "$_id.includes", "$_id.excludes" ] }, _id:0 } }
], (err, data) => {
if (err) {
res.status(500).send(error);
} else {
res.json(data);
}
})
},
答案 0 :(得分:0)
如果两个数组都没有通过$exists
的任何元素,则最有效地排除文档,最重要的是,您需要$ifNull
替换为数组不存在的null
experienceModel.aggregate([
// Don't include documents that have no arrays
{ "$match": {
"$or": [
{ "includes.0": { "$exists": true } },
{ "excludes.0": { "$exists": true } }
]
},
// Join the arrays and exclude the nulls
{ "$project": {
"_id": 0,
"list": {
"$setDifference": [
{ "$setUnion": [
{ "$ifNull": [ "$includes", [null] ] },
{ "$ifNull": [ "$excludes", [null] ] }
]},
[null]
]
}},
// Unwind. By earlier conditions the array must have some entries
{ "$unwind": "$list" },
// And $group on the list values as the key to produce distinct results
{ "$group": { "_id": "$list" }
],(err, data) => {
// rest of code
})
所以第一个$match
是要过滤的,这样至少有一个数组必须作为逻辑规则存在,这也可能加快速度。接下来,使用$setUnion
加入数组,如果字段不存在,请小心使用$ifNull
替换为单个元素[null]
的数组。如果您没有这样做,那么任何$setUnion
结果都将是null
,而不是列出任一数组的条目。所以这非常重要。
由于$setUnion
的输出可能在其列表中包含null
项,因此您可以使用$setDifference
删除该项,这是最短的形式过滤器,您可以编写并使用" sets"。
真正剩下的就是"去标准化"使用[$unwind][6]
将每个文档中的数组转换为每个元素的单个文档,并且我们不需要像preserveNullAndEmptyArrays
这样的新选项,因为上面的所有逻辑都已经开始了。然后,最后$group
就是在这些值上完成,以便产生" unique"输出,这是$group
语句中_id
键的用途。
如果您愿意,那么您甚至可以使用.map()
将结果从聚合中删除到您的回复的简单字符串列表中:
data = data.map( d => d._id );
然后你的所有服务返回都是一个字符串数组,没有嵌入式结构。
[
"Breakfast"
"Airport Pickup"
"Dinner"
"Accomodation"
]