MongoDB 非任何运算符

问题描述 投票:0回答:1

是否有类似于 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

的提示


改进2

再次,作为

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) => {
    
  });


改善3

我发现,我可以使用

$setDifference

和一个 $size 而不是

$setInsersection
和两个
$size
。代码现在看起来像这样:
return this.construct.aggregate({
  $redact: {
    $cond: {
      if: {
        $gt: [{$size: {$setDifference: ['$questionIds', usedQuestionIds]}}, 0]
      },
      then: "$$KEEP",
      else: "$$PRUNE"
    }
  }})
  .exec()
  .then((constructs) => {
    
  });


mongodb mongoose mongodb-query aggregation-framework
1个回答
1
投票

$not

 + 
$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); });

© www.soinside.com 2019 - 2024. All rights reserved.