【问题标题】:How to join query in mongodb?如何在mongodb中加入查询?
【发布时间】:2011-06-01 13:59:13
【问题描述】:

我有这样的用户文档集合:

User {
   id:"001"
   name:"John",
   age:30,
   friends:["userId1","userId2","userId3"....]
}

一个用户有很多朋友,我在SQL中有如下查询:

select * from user where in (select friends from user where id=?) order by age

我想在 MongoDB 中有类似的东西。

【问题讨论】:

标签: join mongodb schema


【解决方案1】:

您可以在 Moongoose JS 中使用 .populate(){ populate : { path : 'field' } }。 示例:

型号:

 mongoose.model('users', new Schema({
        name:String,
        status: true,
        friends: [{type: Schema.Types.ObjectId, ref:'users'}], 
        posts: [{type: Schema.Types.ObjectId, ref:'posts'}], 

    }));
 mongoose.model('posts', new Schema({
            description: String,
            comments: [{type: Schema.Types.ObjectId, ref:'comments'}], 

        }));
 mongoose.model('comments', new Schema({
            comment:String,
            status: true

        }));

如果你想看你朋友的帖子,你可以用这个。

Users.find().                    //Collection 1
        populate({path:'friends',   //Collection 2
        populate:{path:'posts'   //Collection 3
        }})
    .exec();

如果你想看你朋友的帖子,还想把所有的cmet都带上,你也可以用这个,也可以,如果没有找到,查询错误,你可以识别收藏。

 Users.find().                                    //Collection 1
        populate({path:'friends',                 //Collection 2
        populate:{path:'posts',                   //Collection 3
        populate:{path:'commets, model:Collection'//Collection 4 and more
        }}})
    .exec();

最后,如果您只想获取某个 Collection 的某些字段,您可以使用属性选择示例:

Users.find().                                    
        populate({path:'friends', select:'name status friends'                  
        populate:{path:'comments'               
        }})
    .exec();

【讨论】:

    【解决方案2】:

    编辑:此答案仅适用于 v3.2 之前的 MongoDb 版本。

    您无法在一个查询中完成您想做的事情。您必须首先检索朋友用户 ID 列表,然后将这些 ID 传递给第二个查询以检索文档并按年龄对其进行排序。

    var user = db.user.findOne({"id" : "001"}, {"friends": 1})
    db.user.find( {"id" : {$in : user.friends }}).sort("age" : 1);
    

    【讨论】:

    • 请注意,问题中发布的 SQL 也是两个查询(尽管可能有一个组织更好的查询,即朋友表)
    • 我认为,如果您将其转换为“正确”的数据库,任何了解数据库设计和规范化的人都会自动将其放入单独的表中。
    • 实际上,最好在 sql 端使用关系实体,这样您就可以选择用户。* from users join friends on friends.friend_id = users.id and friends.user_id = ?按 users.age 排序...而不是两个有效的用户表 ...
    【解决方案3】:

    仅填充数组好友。

    User.findOne({ _id: "userId"})
    .populate('friends')
    .exec((err, user) => {
        //do something
    });
    

    结果是这样的:

    {
        "_id" : "userId",
        "name" : "John",
        "age" : 30,
        "friends" : [
            { "_id" : "userId1", "name" : "Derek", "age" : 34 }
            { "_id" : "userId2", "name" : "Homer", "age" : 44 }
            { "_id" : "userId3", "name" : "Bobby", "age" : 12 }
        ]
    }
    

    同理:Mongoose - using Populate on an array of ObjectId

    【讨论】:

      【解决方案4】:

      您可以使用mongo-join-query 一次性完成。下面是它的样子:

      const joinQuery = require("mongo-join-query");
      
      joinQuery(
          mongoose.models.User,
          {
              find: {},
              populate: ["friends"],
              sort: { age: 1 },
          },
          (err, res) => (err ? console.log("Error:", err) : console.log("Success:", res.results))
      );
      

      结果将使您的用户按年龄排序并嵌入所有朋友对象。

      它是如何工作的?

      在幕后mongo-join-query 将使用您的 Mongoose 架构来确定要加入哪些模型,并将创建一个 aggregation pipeline 来执行联接和查询。

      【讨论】:

        【解决方案5】:

        要使用聚合框架的 $lookup 功能只需一个查询即可获得所有内容,请尝试以下操作:

        db.User.aggregate(
            [
                // First step is to extract the "friends" field to work with the values
                {
                    $unwind: "$friends"
                },
                // Lookup all the linked friends from the User collection
                {
                    $lookup:
                    {
                        from: "User",
                        localField: "friends",
                        foreignField: "_id",
                        as: "friendsData"
                    }
                },
                // Sort the results by age
                {
                    $sort: { 'friendsData.age': 1 }
                },
                // Get the results into a single array
                {
                    $unwind: "$friendsData"
                },
                // Group the friends by user id
                {
                    $group:
                    {
                        _id: "$_id",
                        friends: { $push: "$friends" },
                        friendsData: { $push: "$friendsData" }
                    }
                }
            ]
        )
        

        假设您的用户集合的内容如下:

        {
            "_id" : ObjectId("573b09e6322304d5e7c6256e"),
            "name" : "John",
            "age" : 30,
            "friends" : [
                "userId1",
                "userId2",
                "userId3"
            ]
        }
        { "_id" : "userId1", "name" : "Derek", "age" : 34 }
        { "_id" : "userId2", "name" : "Homer", "age" : 44 }
        { "_id" : "userId3", "name" : "Bobby", "age" : 12 }
        

        查询的结果将是:

        {
            "_id" : ObjectId("573b09e6322304d5e7c6256e"),
            "friends" : [
                "userId3",
                "userId1",
                "userId2"
            ],
            "friendsData" : [
                {
                    "_id" : "userId3",
                    "name" : "Bobby",
                    "age" : 12
                },
                {
                    "_id" : "userId1",
                    "name" : "Derek",
                    "age" : 34
                },
                {
                    "_id" : "userId2",
                    "name" : "Homer",
                    "age" : 44
                }
            ]
        }
        

        【讨论】:

        • 很好,我很困惑如何对集合中的一个项目执行这样的操作(findOne 等效项在哪里)?编辑:似乎 $match 可能会这样做
        • 我想知道这是否比 2 个查询更有效,因为 $match 不会像 findOne 那样停止搜索。我想知道上面的$limit 是否会有所帮助。
        【解决方案6】:

        https://docs.mongodb.org/manual/reference/operator/aggregation/lookup/

        这是 mongodb 中连接查询的文档,这是 3.2 版的新功能。

        所以这会很有帮助。

        【讨论】:

          【解决方案7】:
          var p = db.sample1.find().limit(2) , 
              h = [];
          for (var i = 0; i < p.length(); i++) 
          {
            h.push(p[i]['name']);
          }
          db.sample2.find( { 'doc_name': { $in : h } } ); 
          

          它对我有用。

          【讨论】:

            【解决方案8】:

            在 mongoDB 中加入查询的一种方法是在一个集合中询问匹配的 id,将 id 放入列表 (idlist) 中,并使用 $in 查找其他(或相同)集合:idlist

            u = db.friends.find({"friends": ? }).toArray()
            idlist= []
            u.forEach(function(myDoc) { idlist.push(myDoc.id ); } )
            db.friends.find({"id": {$in : idlist} } )
            

            【讨论】:

            • 解释可能会有所帮助。
            【解决方案9】:

            您可以使用 playOrm 在一个查询中执行您想要的操作(使用 S-SQL Scalable SQL)。

            【讨论】:

            • 我想问题不在于选择工具(我认为这些家伙毕竟没有发明魔杖)。
            • 是的,但总是很高兴知道/有更多选择......我个人知道我很欣赏这样的答案。
            【解决方案10】:

            MongoDB 没有连接,但在你的情况下你可以这样做:

            db.coll.find({friends: userId}).sort({age: -1})
            

            【讨论】:

            • 你好,我不明白你,我想得到指定用户的朋友,并按年龄对这些朋友进行排序。
            • 嗨,我已经阅读了 mongodb.org/display/DOCS/Querying,但我找不到解决方案..所以我在这里提问。
            • 如果朋友列表是对称的,这是一个正确的解决方案:如果 A 是 B 的朋友,那么 B 将是 A 的朋友。pingw33n 在这里所做的就是说:给我所有用户谁有userId 作为朋友。所以这不是寻找用户,而是寻找他们的朋友。如果您的友谊关系不是对称的(如果它是 Twitter 等跟随类型的关系,那么您将不得不采用 dannie.t 的方法,分两个阶段进行。或者为反向关系添加一个字段(例如,'friendedBy')并以这种方式进行。这是“反规范化”:以多种方式存储相同的数据以提高速度。
            • 在 MongoDB 3.2 中你可以使用聚合函数 ($lookup),它会离开连接
            猜你喜欢
            • 1970-01-01
            • 2012-01-14
            • 2019-08-17
            • 1970-01-01
            • 2021-11-22
            • 1970-01-01
            • 1970-01-01
            • 2016-04-20
            相关资源
            最近更新 更多