简体   繁体   English

查询依赖于mongodb中其他文档的值的文档

[英]query documents that depend on values of other documents in mongodb

Imagine following mongoose model: 想象以下猫鼬模型:

const UserSchema = Schema({
  //_id: ObjectId,
  //more fields,
  blockedIds: [{
    type: ObjectId,
    ref: 'User'
  }]
})

What is the most efficient way to get all users that don't match the blockedIds of an user with a certain _id? 获取与某个_id用户的blockId不匹配的所有用户的最有效方法是什么?

A naive way would be to to perform two queries: 天真的方法是执行两个查询:

User.findById(id).then(user => {
  return User.find({_id: {$nin: user.blockedIds}})
})

Is it possible to use the aggregation framework and $facets to accomplish that in one query? 是否可以使用聚合框架和$ facets在一个查询中完成此操作?

Try non-correlated sub query from 3.6 for your use case. 尝试从3.6开始使用不相关的子查询作为您的用例。

Something like 就像是

User.aggregate(
 [{$lookup:{
   from: "users",
   pipeline:[
    {$match: {_id:mongoose.Types.ObjectId(id)}},
    {$project: {_id:0,blockedIds:1}}
   ],
   as: "noncr"
 }},
 {$match:{
   $expr:{
     $not:[
      {$in:[
        $_id,
        {$arrayElemAt:["$noncr.blockedIds",0]}
      ]}
    ]
  }
}},
{$project:{noncr:0}}]
)

$lookup to pull in the "blockedIds" for input id followed by $match to filter the documents where "_id" is not in list of blockedIds. $lookup提取输入ID的“ blockedIds”,然后输入$match过滤“ _id”不在blockedId列表中的文档。

$expr allows use of aggregation comparison operators in $match stage. $expr允许在$ match阶段使用聚合比较运算符。

$arrayElemAt to fetch the first element from $lookup array. $arrayElemAt从$ lookup数组中获取第一个元素。

$in to compare the _id against blockedIds. $in比较_id与blockedIds。

$project with exclusion to remove the "noncr" field from the final response. $project排除在外,以从最终响应中删除“ noncr”字段。

Please note when you test query use the collection name not model or schema name in "from" attribute of look up stage. 请注意,当您测试查询时,请在查找阶段的“来自”属性中使用集合名称而不是模型名称或架构名称。

The aggregation framework in the other answer is useful, but for the sake of completeness, here's an alternate approach. 另一个答案中的聚合框架很有用,但是出于完整性考虑,这是另一种方法。 In Redis db designs, you always have to think of accessing the data from "both ways", so you think of inverting results. 在Redis db设计中,您始终必须考虑从“双向”访问数据,因此您要考虑反转结果。 So that's what we can do here. 这就是我们在这里可以做的。

Instead of having blockedIds array on user, have a blockedBy : 而不是在用户上使用blockedIds数组,而是使用blockedBy

const UserSchema = Schema({
  blockedBy: [{
    type: ObjectId,
    ref: 'User',
    index: true,
  }]
});

So now you invert the problem and the query becomes trivial: 因此,现在您将问题反转了,查询变得无关紧要了:

User.find({ userID: { $nin: blockedBy: } });

In some situations it could be a viable option. 在某些情况下,这可能是一个可行的选择。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM