MongoDB不是任何运营商

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数组。我现在尝试查询所有结

mongodb查询是否有类似于not any运算符的功能

我有以下设置:

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
更好。我再次更新了我的问题