MongoDB不是任何运营商
mongodb查询是否有类似于not any运算符的功能 我有以下设置:MongoDB不是任何运营商,mongodb,mongoose,mongodb-query,aggregation-framework,Mongodb,Mongoose,Mongodb Query,Aggregation Framework,mongodb查询是否有类似于not any运算符的功能 我有以下设置: const ConstructQuestion = new Schema({ answerType: String, text: String, }); const Construct = new Schema({ name: String, description: String, questions: [ConstructQuestion], }); 我还有一个问题ID数组。我现在尝试查询所有结
const ConstructQuestion = new Schema({
answerType: String,
text: String,
});
const Construct = new Schema({
name: String,
description: String,
questions: [ConstructQuestion],
});
我还有一个问题ID数组。我现在尝试查询所有结构,其中包含\u id
不在我的ConstructQuestionID数组中的任何问题
换句话说:我希望所有结构都有\u id
为的问题,而不是数组中的任何id
我可以使用$in
实现与我想要的相反的效果,它查询所有结构,这些结构有任何问题,其\u id
是我id数组中id的任何。遗憾的是,$nin
不是答案,因为它与包含我的ID数组中所有问题的结构不匹配
编辑: 确切地说:我正在寻找一个查询,该查询将为我提供所有构造,其中至少包含一个id在我的id数组中为而非的问题
结果: 在s answer的帮助下,我的猫鼬解决方案现在看起来如下:
return this.construct.aggregate()
.group({
_id: '$_id',
questions_id: {$push: '$questions._id'},
construct: {$first: '$$ROOT'},
})
.unwind('$questions_id')
.project({
construct: true,
questions_id: true,
check: {
$cmp: [{
$size: {$setIntersection: ['$questions_id', usedQuestionIds]},
}, {
$size: '$questions_id',
}],
},
})
.match({check: {$lt: 0}})
.exec()
.then((results) => {
const constructs = results.map((result) => {
return result.construct;
});
})
return this.construct.aggregate({
$addFields: {
check: {
$cmp: [{
$size: {$setIntersection: ['$questionIds', usedQuestionIds]},
}, {
$size: '$questionIds',
}],
},
}})
.match({check: {$lt: 0}})
.exec()
.then((constructs) => {
});
return this.construct.aggregate({
$redact: {
$cond: {
if: {
$lt: [
{$size: {$setIntersection: ['$questionIds', usedQuestionIds]}},
{$size: '$questionIds'}
]
},
then: '$$KEEP',
else: '$$PRUNE'
}
}})
.exec()
.then((constructs) => {
});
return this.construct.aggregate({
$redact: {
$cond: {
if: {
$gt: [{$size: {$setDifference: ['$questionIds', usedQuestionIds]}}, 0]
},
then: "$$KEEP",
else: "$$PRUNE"
}
}})
.exec()
.then((constructs) => {
});
改进: 在每次创建/更新时将QuestionID作为数组直接添加到构造之后,我可以删除
组
和放松
阶段,因此我的代码现在如下所示:
return this.construct.aggregate()
.group({
_id: '$_id',
questions_id: {$push: '$questions._id'},
construct: {$first: '$$ROOT'},
})
.unwind('$questions_id')
.project({
construct: true,
questions_id: true,
check: {
$cmp: [{
$size: {$setIntersection: ['$questions_id', usedQuestionIds]},
}, {
$size: '$questions_id',
}],
},
})
.match({check: {$lt: 0}})
.exec()
.then((results) => {
const constructs = results.map((result) => {
return result.construct;
});
})
return this.construct.aggregate({
$addFields: {
check: {
$cmp: [{
$size: {$setIntersection: ['$questionIds', usedQuestionIds]},
}, {
$size: '$questionIds',
}],
},
}})
.match({check: {$lt: 0}})
.exec()
.then((constructs) => {
});
return this.construct.aggregate({
$redact: {
$cond: {
if: {
$lt: [
{$size: {$setIntersection: ['$questionIds', usedQuestionIds]}},
{$size: '$questionIds'}
]
},
then: '$$KEEP',
else: '$$PRUNE'
}
}})
.exec()
.then((constructs) => {
});
return this.construct.aggregate({
$redact: {
$cond: {
if: {
$gt: [{$size: {$setDifference: ['$questionIds', usedQuestionIds]}}, 0]
},
then: "$$KEEP",
else: "$$PRUNE"
}
}})
.exec()
.then((constructs) => {
});
再次感谢您的提示
改进2 同样,作为来自的提示,
$project
和$match
可以(在本例中)组合为$redact
,代码现在如下所示:
return this.construct.aggregate()
.group({
_id: '$_id',
questions_id: {$push: '$questions._id'},
construct: {$first: '$$ROOT'},
})
.unwind('$questions_id')
.project({
construct: true,
questions_id: true,
check: {
$cmp: [{
$size: {$setIntersection: ['$questions_id', usedQuestionIds]},
}, {
$size: '$questions_id',
}],
},
})
.match({check: {$lt: 0}})
.exec()
.then((results) => {
const constructs = results.map((result) => {
return result.construct;
});
})
return this.construct.aggregate({
$addFields: {
check: {
$cmp: [{
$size: {$setIntersection: ['$questionIds', usedQuestionIds]},
}, {
$size: '$questionIds',
}],
},
}})
.match({check: {$lt: 0}})
.exec()
.then((constructs) => {
});
return this.construct.aggregate({
$redact: {
$cond: {
if: {
$lt: [
{$size: {$setIntersection: ['$questionIds', usedQuestionIds]}},
{$size: '$questionIds'}
]
},
then: '$$KEEP',
else: '$$PRUNE'
}
}})
.exec()
.then((constructs) => {
});
return this.construct.aggregate({
$redact: {
$cond: {
if: {
$gt: [{$size: {$setDifference: ['$questionIds', usedQuestionIds]}}, 0]
},
then: "$$KEEP",
else: "$$PRUNE"
}
}})
.exec()
.then((constructs) => {
});
改进3 我发现,我可以使用和一个
$size
,而不是$setInsersection
和两个$size
。代码现在如下所示:
return this.construct.aggregate()
.group({
_id: '$_id',
questions_id: {$push: '$questions._id'},
construct: {$first: '$$ROOT'},
})
.unwind('$questions_id')
.project({
construct: true,
questions_id: true,
check: {
$cmp: [{
$size: {$setIntersection: ['$questions_id', usedQuestionIds]},
}, {
$size: '$questions_id',
}],
},
})
.match({check: {$lt: 0}})
.exec()
.then((results) => {
const constructs = results.map((result) => {
return result.construct;
});
})
return this.construct.aggregate({
$addFields: {
check: {
$cmp: [{
$size: {$setIntersection: ['$questionIds', usedQuestionIds]},
}, {
$size: '$questionIds',
}],
},
}})
.match({check: {$lt: 0}})
.exec()
.then((constructs) => {
});
return this.construct.aggregate({
$redact: {
$cond: {
if: {
$lt: [
{$size: {$setIntersection: ['$questionIds', usedQuestionIds]}},
{$size: '$questionIds'}
]
},
then: '$$KEEP',
else: '$$PRUNE'
}
}})
.exec()
.then((constructs) => {
});
return this.construct.aggregate({
$redact: {
$cond: {
if: {
$gt: [{$size: {$setDifference: ['$questionIds', usedQuestionIds]}}, 0]
},
then: "$$KEEP",
else: "$$PRUNE"
}
}})
.exec()
.then((constructs) => {
});
我想你要找的是+: 它将返回尚未在input
input
array中指定所有问题的所有文档。如果选择文档,则表示输入
数组中至少有一个问题不在文档中
编辑
由于您希望交叉点与问题
文档完全匹配,因此可以使用“聚合中可用”来确定两个数组共有的元素,并根据这些元素做出决策:
var array = [
new mongoose.mongo.ObjectId("58c20f6d95b16e3046ddd7e9"),
new mongoose.mongo.ObjectId("58c20f6d95b16e3046ddd7ea"),
new mongoose.mongo.ObjectId("58c20f6d95b16e3046ddd7eb"),
new mongoose.mongo.ObjectId("58c20f6d95b16e3046ddd7ec")
];
Const.aggregate([{
$group: {
"_id": "$_id",
"questions_id": {
$push: "$questions._id"
},
"document": { $first: "$$ROOT" }
}
}, {
$unwind: "$questions_id"
}, {
$project: {
document: 1,
questions_id: 1,
check: {
$cmp: [{
$size: {
$setIntersection: ["$questions_id", array]
}
}, {
$size: "$questions_id"
}]
}
}
}, {
$match: {
check: {
"$lt": 0
}
}
}], function(err, res) {
console.log(res);
});
第一个$group
和$unwind
负责构建一系列问题。将在下一个$project
中与交叉点大小和问题的大小进行比较
编辑2
您可以简化$project
+$match
,使用将保持数据与条件匹配的。通过新添加的questionID
字段,它变得简单得多:
var array = [
new mongoose.mongo.ObjectId("58c20f6d95b16e3046ddd7e9"),
new mongoose.mongo.ObjectId("58c20f6d95b16e3046ddd7ea"),
new mongoose.mongo.ObjectId("58c20f6d95b16e3046ddd7eb"),
new mongoose.mongo.ObjectId("58c20f6d95b16e3046ddd7ec")
];
Const.aggregate([{
$redact: {
$cond: {
if: {
$lt: [{
$size: {
$setIntersection: ["$questionIds", array]
}
}, {
$size: "$questionIds"
}]
},
then: "$$KEEP",
else: "$$PRUNE"
}
}
}], function(err, res) {
console.log(res);
});
是mongoDB特性,这些管道阶段由mongoDB执行。为了提高性能,最好在第一阶段包含一个$match
,因为$group
是操作密集型的,因为它将对所有数据库文档进行分组,只需在每个构造创建和更新上设置问号,我已成功删除组并展开阶段:)将把此信息添加到我的问题中。请参阅我更新的帖子,以将$project
+$match
替换为$redact
漂亮!工作很有魅力,我相应地更新了我的问题。伙计,我今天真的学到了很多关于聚合的知识:)使用$setDifference
似乎比$setcrossion
更好。我再次更新了我的问题