MongoDB一次查询多个集合

Posted

技术标签:

【中文标题】MongoDB一次查询多个集合【英文标题】:MongoDB query multiple collections at once 【发布时间】:2011-09-24 01:22:47 【问题描述】:
users

 "_id":"12345",
 "admin":1
,

 "_id":"123456789",
 "admin":0


posts

 "content":"Some content",
 "owner_id":"12345",
 "via":"facebook"
,

 "content":"Some other content",
 "owner_id":"123456789",
 "via":"facebook"

这是我的 mongodb 中的一个示例。我想获取所有具有“via”属性等于“facebook”并由管理员(“admin”:1)发布的帖子。我不知道如何获取此查询。由于 mongodb 不是关系型数据库,所以无法进行连接操作。有什么解决办法?

【问题讨论】:

【参考方案1】:

执行多个查询或使用嵌入文档或查看“数据库引用”。

【讨论】:

【参考方案2】:

尝试在 MongoDB 中加入会破坏使用 MongoDB 的目的。但是,您可以使用 DBref 并编写您的应用程序级代码(或库),以便它自动为您获取这些引用。

或者您可以更改架构并使用embedded documents。

您的最终选择是保持原样并执行两个查询。

【讨论】:

如何为此编写两个查询? Doctrine MongoDB ODM 是处理此类事情的一个不错的库。但是,它只允许您通过一层参考加入;您不能以任何程度的语法轻松在引用中填充引用中的引用。 如何在 MongoJS 中使用普通的旧查询来实现这一点? 您现在可以使用$lookup 加入 对不起,但我只想说,“尝试使用没有 JOIN 概念的数据库违背了数据库的目的。完全” Mongo 添加了 $lookup 因为错误地假设这不是案子。嵌入式文档不是最佳答案,因为它们与它们应该等效的记录不同步,并且您最终会复制数据。【参考方案3】:

一种解决方案:将 isAdmin: 0/1 标志添加到您的帖子收集文档中。

其他解决方案:使用 DBrefs

【讨论】:

【参考方案4】:

正如之前在 MongoDB 中提到的,你不能在集合之间加入。

对于您的示例,解决方案可能是:

var myCursor = db.users.find(admin:1);
var user_id = myCursor.hasNext() ? myCursor.next() : null;
db.posts.find(owner_id : user_id._id);

请参阅参考手册 - 光标部分:http://es.docs.mongodb.org/manual/core/cursors/

其他解决方案是将用户嵌入帖子集合中,但我认为对于大多数 Web 应用程序,用户集合出于安全原因需要独立。用户集合可能有角色、权限等。

posts

 "content":"Some content",
 "user":"_id":"12345", "admin":1,
 "via":"facebook"
,

 "content":"Some other content",
 "user":"_id":"123456789", "admin":0,
 "via":"facebook"

然后:

db.posts.find(user.admin: 1 );

【讨论】:

【参考方案5】:

这里是您问题的答案。

db.getCollection('users').aggregate([
    $match : admin : 1,
    $lookup: from: "posts",localField: "_id",foreignField: "owner_id",as: "posts",
    $project : 
            posts :  $filter : input : "$posts"  , as : "post", cond :  $eq : ['$$post.via' , 'facebook']   ,
            admin : 1

        

])

或者您可以使用 mongodb 组选项。

db.getCollection('users').aggregate([
    $match : admin : 1,
    $lookup: from: "posts",localField: "_id",foreignField: "owner_id",as: "posts",
    $unwind : "$posts",
    $match : "posts.via":"facebook",
     $group : 
            _id : "$_id",
            posts : $push : "$posts"
    
])

【讨论】:

这是做什么的?这是一个查询还是将元数据添加到集合中? $lookup 运算符是自 3.2 版以来的新功能,类似于左外连接。见docs.mongodb.com/manual/reference/operator/aggregation/lookup【参考方案6】:

您可以使用$lookup (multiple) 从多个集合中获取记录:

例子:

如果您有更多收藏(我这里有 3 个用于演示的收藏,您可以拥有 3 个以上)。我想从单个对象中的 3 个集合中获取数据:

集合如下:

db.doc1.find().pretty();


    "_id" : ObjectId("5901a4c63541b7d5d3293766"),
    "firstName" : "shubham",
    "lastName" : "verma"

db.doc2.find().pretty();


    "_id" : ObjectId("5901a5f83541b7d5d3293768"),
    "userId" : ObjectId("5901a4c63541b7d5d3293766"),
    "address" : "Gurgaon",
    "mob" : "9876543211"

db.doc3.find().pretty();


    "_id" : ObjectId("5901b0f6d318b072ceea44fb"),
    "userId" : ObjectId("5901a4c63541b7d5d3293766"),
    "fbURLs" : "http://www.facebook.com",
    "twitterURLs" : "http://www.twitter.com"

现在您的查询将如下所示:

db.doc1.aggregate([
     $match:  _id: ObjectId("5901a4c63541b7d5d3293766")  ,
    
        $lookup:
        
            from: "doc2",
            localField: "_id",
            foreignField: "userId",
            as: "address"
        
    ,
    
        $unwind: "$address"
    ,
    
        $project: 
            __v: 0,
            "address.__v": 0,
            "address._id": 0,
            "address.userId": 0,
            "address.mob": 0
        
    ,
    
        $lookup:
        
            from: "doc3",
            localField: "_id",
            foreignField: "userId",
            as: "social"
        
    ,
    
        $unwind: "$social"
    ,

     
    $project:       
           __v: 0,      
           "social.__v": 0,      
           "social._id": 0,      
           "social.userId": 0
       
 

]).pretty();

那么您的结果将是:


    "_id" : ObjectId("5901a4c63541b7d5d3293766"),
    "firstName" : "shubham",
    "lastName" : "verma",

    "address" : 
        "address" : "Gurgaon"
    ,
    "social" : 
        "fbURLs" : "http://www.facebook.com",
        "twitterURLs" : "http://www.twitter.com"
    

如果您想要每个集合中的所有记录,那么您应该从查询中删除以下行:


            $project: 
                __v: 0,
                "address.__v": 0,
                "address._id": 0,
                "address.userId": 0,
                "address.mob": 0
            
        

   
        $project:       
               "social.__v": 0,      
               "social._id": 0,      
               "social.userId": 0
           
     

删除以上代码后,总记录如下:


    "_id" : ObjectId("5901a4c63541b7d5d3293766"),
    "firstName" : "shubham",
    "lastName" : "verma",
    "address" : 
        "_id" : ObjectId("5901a5f83541b7d5d3293768"),
        "userId" : ObjectId("5901a4c63541b7d5d3293766"),
        "address" : "Gurgaon",
        "mob" : "9876543211"
    ,
    "social" : 
        "_id" : ObjectId("5901b0f6d318b072ceea44fb"),
        "userId" : ObjectId("5901a4c63541b7d5d3293766"),
        "fbURLs" : "http://www.facebook.com",
        "twitterURLs" : "http://www.twitter.com"
    

【讨论】:

嗨,@Shubham Verma,如何从“社交”或“地址”集合中获取多条记录。在同一个查询中。就像我在单个用户的社交收藏中有多条记录

以上是关于MongoDB一次查询多个集合的主要内容,如果未能解决你的问题,请参考以下文章

基于多个子文档的MongoDB/Mongoose查询

mongodb高级查询

提高一个字段与多个集合比较的效率 Mongodb Jdbc

mongodb怎么插入多个文档

如何使用graphql将mongodb中多个集合中的数据传递到1个反应表

MongoDB - 聚合查询