$lookup 运算符未能返回来自多个集合的组合数据

Posted

技术标签:

【中文标题】$lookup 运算符未能返回来自多个集合的组合数据【英文标题】:$lookup operator has failed to return the combined data from multiple collections 【发布时间】:2018-04-14 14:15:39 【问题描述】:

我不明白为什么我的聚合管道未能合并多个集合(cmets 和用户)。我正在尝试返回 cmets 集合中每个 userId 的用户名。 MongoDB版本.... v3.0.7

.get(function(req,res)
      //returning aggregate values from comments part.. comment.authorId must hv user.username.
       CardComment.aggregate([ //*** qn... ask tomorrow  show the models
           //now perform the mongo join  of multiple collections like in SQL Joins
           
             $lookup:
                from: 'users', //external collection.
                localField: 'authorId', //input field., from current collection.. cardComments
                foreignField: '_id', //foreign key from external collection,
                as: 'commentUser'
             
           ,
           //filter according to the cardId.. part. find()... first pipeline
           
             $match:"card": req.params.cardId 
           

       ], function(err,comments)
         if (err) 
            res.json("success":false, "message": 'Error in loading comments')
          else 
             //res.json("success": true, "message": comments)
              console.log(JSON.stringify(comments))
            //console.log(comments) //u need to ask for help on ***.
         
       )

    )

对于我使用 mongoose 模块的 MongoDB 模式, 我已经缩短了它以使问题更小。 cardComments 集合架构

authorId:
      type: ObjectId,
      ref : 'User',
      required: true
    ,
    createdAt: 
       type: Date,
       default: Date.now
    

然后用于用户集合。

var UserSchema = new Schema(
username:  type: String, required: true, lowercase: true, index:  unique: true  ,
email:  type: String, required: true, index:  unique: true  ,
//password:  type: String, required: true   u forgot the select field.. that z why login was disturbing
 password: type: String, select: false //that z why u need postman to test stuff
);

我有兴趣在 cmets 集合的 authorId 部分显示用户集合中的用户名字段。 谢谢

【问题讨论】:

失败了怎么办?没有结果? $lookup 失败还是 $match 失败?您是否检查过以确保 userId 实际上与外部集合中的 _id 类型相同(通常两者都需要为 ObjectId )。最常见的错误是一个存储为“字符串”,另一个存储为ObjectId 在您的 comment 架构中是 card ObjectId 吗? 【参考方案1】:

如图所示,您使用了 ObjectId 的架构,它应该是像 mongoose.Schema.Types.ObjectId 这样的猫鼬 ob​​jectId。然后$lookup 应该可以工作。如果cardId 也是ObjectId,那么您必须将其转换为猫鼬ObjectId 才能在$match 阶段使用。如果cardId 在您的comments 架构中,那么您应该首先使用$match 阶段来解决性能问题。

所以你的模型应该是这样的

authorId:
  type: mongoose.Schema.Types.ObjectId, 
  ref : 'User',
  required: true

和你的功能

get(function (req, res) 
  // if cardId is ObjectId type
  let cardId = mongoose.Types.ObjectId(req.params.cardId);
  CardComment.aggregate([
    
      $match: "card": cardId
    ,
    
      $lookup: 
        from: 'users',
        localField: 'authorId',
        foreignField: '_id',
        as: 'commentUser'
      
    
  ], function (err, comments) 
    if (err) 
      res.json("success": false, "message": 'Error in loading comments')
     else 
      console.log(JSON.stringify(comments))
    
  )
)

【讨论】:

感谢您的建议。正如@Neil Lunn 所指出的,我应该检查我检查的错误消息,这似乎是数据库版本问题。 mongodb 3.0.7 不支持 $lookup。这是我检查时遇到的错误。“成功”:假,“消息”:“名称”:“MongoError”,“消息”:“异常:无法识别的管道阶段名称:'$lookup'”,“ errmsg”:“异常:无法识别的管道阶段名称:'$lookup'”,“code”:16436,“ok”:0 【参考方案2】:

感谢您在我检查 $lookup 运算符的错误消息时所做的努力。感谢您的建议。正如@Neil Lunn 所指出的,我应该检查我检查的错误消息,这似乎是数据库版本问题。 mongodb 3.0.7 不支持 $lookup。这是我检查时遇到的错误。


"success": false,
"message": 
    "name": "MongoError",
    "message": "exception: Unrecognized pipeline stage name: '$lookup'",
    "errmsg": "exception: Unrecognized pipeline stage name: '$lookup'",
    "code": 16436,
    "ok": 0

【讨论】:

以上是关于$lookup 运算符未能返回来自多个集合的组合数据的主要内容,如果未能解决你的问题,请参考以下文章

来自多个集合的 $lookup 和嵌套输出

除了 $lookup 运算符之外,MongoDB 4.0 中加入的替代方法是啥,因为它不适用于分片集合

Python组合数据类型

Python组合数据类型

如何在 mongodb 中使用 $lookup 加入多个集合

Mongoose.aggregate(pipeline) 使用 $unwind、$lookup、$group 链接多个集合