【问题标题】:Mongo Lookup join in collections using $id referenceMongodb Lookup 使用 $id 引用加入集合
【发布时间】:2019-09-13 23:36:59
【问题描述】:

我有一个名为 post 的集合,其中引用了另外两个集合:状态、格式

post:
{
    "_id" : ObjectId("5d7c1c4549c5e277395871ad"),
    "status" : {
        "$ref" : "status",
        "$id" : ObjectId("status123")
    },
    "format" : {
        "$ref" : "format",
        "$id" : ObjectId("format123")
    }
}

status:
{
    "_id" : ObjectId("status123"),
    "name" : "Draft"
}

format:
{
    "_id" : ObjectId("format123"),
    "name" : "Standard"
}

我希望 post 查询返回以下内容:

post:
{
    "_id" : ObjectId("5d7c1c4549c5e277395871ad"),
    "status" : {
        "_id" : ObjectId("status123"),
        "name" : "Draft"
    },
    "format" : {
        "_id" : ObjectId("format123"),
        "name" : "Standard"
    }
}

我的 Mongo 查询应该是什么?我是使用 MongoDB 的新手,非常感谢任何帮助。

谢谢, 沙市

【问题讨论】:

    标签: mongodb


    【解决方案1】:

    你的问题

    你可以这样做

     db.post.aggregate([
    {$project :
               { status:
                        {$arrayElemAt:
                                      [{$objectToArray:"$status"},1]
                         },
                format:
                       {$arrayElemAt:
                                      [{$objectToArray:"$format"},1]
                }}},
    {$project:
              {status:"$status.v" ,
              format:"$format.v"}
    },
    
    {$lookup : 
              {from :"status" ,
               localField : "status",
                foreignField:"_id" ,
               as :"status"}
    },
    {$lookup:
              {from :"format" ,
              localField:"format",
              foreignField:"_id",
               as:"format"}
    },
    {$unwind :"$status"},
    {$unwind:"$format"}
    ])
    

    结果看起来像

    { "_id" : ObjectId("5d7c1c4549c5e277395871ad"),
    "status" : { 
               "_id" : ObjectId("5d7c4af7c45316e35251a499"),
                 "name" : "Draft" 
                },
     "format" : { 
               "_id" : ObjectId("5d7c4b21c45316e35251a49a"),
                "name" : "Standard" 
               } 
    }
    

    解释

    stage1 : 使用$objectToArray 将文档转换为数组,我们使用它来转换DBref ;
    stage2:使用$arrayElemAt$project获取链接的“_id”。

    stage3 : 使用$lookup 加入两个集合
    stage4 : 使用$unwind 获取内部文档。从输入文档中解构一个数组字段,为每个元素输出一个文档。

    【讨论】:

    • 为什么要使用$objectToArray...?在这种情况下有点矫枉过正,不是吗?
    • @HbnKing 当我使用 $unwind 时,我看到我所有的帖子都没有返回,并且一些帖子在结果中显示了多次。我希望我所有的帖子都只返回一次。我可以删除 $unwind,这似乎解决了我的目的吗?
    • @BuzzMoschetti 你说的 $objectToArray 是什么意思是大材小用?您有更好的解决方案吗?
    • ?是的,昨天贴在下面。警告:我将 status.$idformat.$id 更改为 status.idformat.id 我不确定 OP 是否不能这样做,但是字段名称中带有前导 $ 的数据设计在使用时会遇到麻烦聚合运算符和字段路径函数。
    • $unwind{ $unwind: { path: "$sizes", preserveNullAndEmptyArrays: true } } 之类的选项一起使用
    【解决方案2】:

    很遗憾,您不能在字段名称中使用$。 但如果我们改用这个:

    var sid1 = new ObjectId();
    var fid1 = new ObjectId();
    
    var postdoc =
    {
        "_id" : ObjectId("5d7c1c4549c5e277395871ad"),
        "status" : {
            "ref" : "status",
            "id" : sid1
        },
        "format" : {
            "ref" : "format",
            "id" : fid1
        }
    };
    
    var statusdoc =
    {
        "_id" : sid1,
        "name" : "Draft"
    };
    
    var formatdoc =
    {
        "_id" : fid1,
        "name" : "Standard"
    };
    
    db.post.insert(postdoc);
    db.status.insert(statusdoc);
    db.format.insert(formatdoc);
    
    

    那么这个查询:

    db.post.aggregate([
    {$lookup: {"from": "status",
                         localField: "status.id",
                         foreignField: "_id",
                         as: "STATUS" }}
    
    ,{$lookup: {"from": "format",
                         localField: "format.id",
                         foreignField: "_id",
                         as: "FORMAT" }}
    
    ,{$project: {
            "status": {$arrayElemAt: [ "$STATUS",0 ] },
            "format": {$arrayElemAt: [ "$FORMAT",0 ] }
        }}
    
                          ]);
    

    产生预期的结果:

    {
        "_id" : ObjectId("5d7c1c4549c5e277395871ad"),
        "status" : {
            "_id" : ObjectId("5d7c921a32c55e3d729b552f"),
            "name" : "Draft"
        },
        "format" : {
            "_id" : ObjectId("5d7c921a32c55e3d729b5530"),
            "name" : "Standard"
        }
    }
    
    

    【讨论】:

      【解决方案3】:
      I could get the desired output using variables.
      
      var post = db.post.findOne({"_id":ObjectId("5d7c8fb8ba38a9196e5fc195")})
      var dbRef = post.status
      var status = db[dbRef.$ref].findOne({"_id":(dbRef.$id)})
      var dbRef1 = post.format
      var format = db[dbRef1.$ref].findOne({"_id":(dbRef1.$id)})
      
      db.post.aggregate({ $project : { "_id" : post._id , "status" : status , "format" : format}})
      

      您可以查看 MongoDB 数据库参考链接以获取更多信息。 https://docs.mongodb.com/manual/reference/database-references/index.html

      【讨论】:

      • 这是到数据库的 3 次单独往返。
      猜你喜欢
      • 2023-03-09
      • 2016-06-19
      • 1970-01-01
      • 2016-07-26
      • 2021-09-17
      • 2018-02-06
      相关资源
      最近更新 更多