是否有类似于 mongodb 查询的 not-any 运算符之类的东西?
我有以下设置:
const ConstructQuestion = new Schema({
answerType: String,
text: String,
});
const Construct = new Schema({
name: String,
description: String,
questions: [ConstructQuestion],
});
我还有一个 ConstructQuestion-ID 数组。我现在尝试查询所有包含
_id
不在我的 ConstructQuestionID-Array 中的问题的所有构造。
换句话说:我想要所有有问题的构造,其
_id
是不是我的数组中的任何ID
我可以使用 $in
实现与我想要的相反的效果,它查询所有具有
_id
是我的 ID 数组中 ID 的any 的任何问题的构造。遗憾的是
$nin
不是答案,因为它与包含我的 ID 数组中的所有问题及更多内容的构造不匹配
编辑:
非常准确地说:我正在寻找一个查询,该查询将为我提供所有包含至少一个问题的构造,其 id 在我的 ID 数组中不是
在
Bertrand的回答的帮助下,我的猫鼬解决方案现在看起来像这样:
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;
});
})
在每次创建/更新时将 QuestionIds 作为数组直接添加到构造中后,我可以删除
group
和
unwind
阶段,所以我的代码现在看起来像这样:return this.construct.aggregate({
$addFields: {
check: {
$cmp: [{
$size: {$setIntersection: ['$questionIds', usedQuestionIds]},
}, {
$size: '$questionIds',
}],
},
}})
.match({check: {$lt: 0}})
.exec()
.then((constructs) => {
});
再次感谢Bertrand
再次,作为
Bertrand 的提示,$project
和
$match
可以(在本例中)组合为 $redact
,代码现在如下所示:return this.construct.aggregate({
$redact: {
$cond: {
if: {
$lt: [
{$size: {$setIntersection: ['$questionIds', usedQuestionIds]}},
{$size: '$questionIds'}
]
},
then: '$$KEEP',
else: '$$PRUNE'
}
}})
.exec()
.then((constructs) => {
});
我发现,我可以使用
$setDifference 和一个 $size
而不是
$setInsersection
和两个 $size
。代码现在看起来像这样:return this.construct.aggregate({
$redact: {
$cond: {
if: {
$gt: [{$size: {$setDifference: ['$questionIds', usedQuestionIds]}}, 0]
},
then: "$$KEEP",
else: "$$PRUNE"
}
}})
.exec()
.then((constructs) => {
});
+
$all
:
var input = ["58c20f6d95b16e3046ddd7e9", "58c20f6d95b16e3046ddd7eb", "58c20f6d95b16e3046ddd7ec"];
Data.find({
"questions._id": {
"$not": {
"$all": input
}
}
}, function(err, res) {
console.log(res);
});
它将返回所有未在输入
input
数组中指定所有问题的文档。如果文档被选中,则意味着
input
数组中至少有一个问题不在文档中。编辑
questions
文档完全匹配时,您可以使用聚合中可用的
setIntersection
来确定两个数组共有的元素,并据此做出决策:
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
负责构建 questions._id
数组。在接下来的$project
中进行交集大小和questions._id
的大小的比较。编辑2
$project
$match
+ $redact
,这将保持文档与条件匹配。有了新添加的
questionIds
字段,事情就简单多了 :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);
});