如何在mongodb中加入查询?

Posted

技术标签:

【中文标题】如何在mongodb中加入查询?【英文标题】:How to join query in 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 中有类似的东西。

【问题讨论】:

也许您需要数据库引用 - docs.mongodb.org/manual/reference/database-references 【参考方案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),它会离开连接

以上是关于如何在mongodb中加入查询?的主要内容,如果未能解决你的问题,请参考以下文章

在烧瓶 mongoDB 中加入集合的 groupby 查询

在查询输出中加入字符串

如何使用 Django 在查询中加入 3 个表

如何在 JPA JPQL 查询中加入两个实体集合?

如何在 Sequelize 查询中加入另一个表

如何在 Cloud Firestore 查询中加入多个文档?