【问题标题】:How to make nested queries in MongoDb that works like nested Sql select queries如何在 MongoDb 中进行类似于嵌套 Sql 选择查询的嵌套查询
【发布时间】:2012-03-27 05:03:44
【问题描述】:

我想在 MongoDb 中进行高效查询,以查找在用户组中列出其用户 ID 的所有用户。理想情况下,我想将此作为对 Mongodb 的单个请求。 我想要的对应于 SQL 中的嵌套选择。 我在 mongo shell 中试过这个:

db.user.save({_id:"u1", Name:"u1 name"});
db.user.save({_id:"u2", Name:"u1 name"});
db.user.save({_id:"u3", Name:"u3 name"});
db.usergroup.save({_id:"g1", Users: ["u2","u3"]});

现在这是我想要做的选择,但没有硬编码 ["u2","u3"] 数组:

db.user.find({_id:{$in:["u2","u3"]}}).forEach(printjson);

这可以正常工作并返回 u2 和 u3 的用户对象。

现在的问题是如何通过查询提取 $in 运算符中的用户 ID 数组,以便可以通过单个请求进行整个查询。

这样的“嵌套查询”不起作用:

db.user.find({_id:{$in:db.usergroup.find({_id:"g1"},{_id:0,Users:1})}}).forEach(printjson);

给出这个错误: 3 月 27 日星期二 06:17:41 未捕获的异常:错误:{“$err”:“无效查询”,“代码”:12580 } 加载失败:mongoNestedSelect.js

1) 这在 mongodb 中是否可行?

2)如何使用官方c#驱动来做到这一点?

【问题讨论】:

    标签: mongodb mongodb-.net-driver


    【解决方案1】:

    在 MongoDB 中,此类问题的答案通常是对您的数据进行非规范化处理。如果您只需要组中的用户列表,您可以将用户 ID 用户名存储在组文档中。在某些方面,您可以根据希望在屏幕上看到的结果来构建数据库,而不是尝试将其置于某种标准化格式。

    显然,只有当您的用户组列表(带有名称)可以放在单个文档中时,这才有效,但是您当前的方法在组的最大大小方面也有一些限制。

    另一种方法是将用户所属的组存储在每个“用户”文档的数组中。在该数组字段上添加索引,现在您可以按组查找用户。鉴于用户所属的组可能少于组中的成员,这可能是这里的最佳方法。

    db.user.save({_id:"u1", name:"u1 name", groups:[{_id:"g1", name:"Group One"}, ...]});
    

    同样,您可以将组名与其 _id 一起存储,这样您就可以通过单次往返立即显示用户所属的组列表。当然,如果您允许更改组名,则必须启动后台任务来修复所有这些名称的副本。

    我也会使用内置的 MongoDB id 生成器而不是您自己的,它有许多理想的属性。

    【讨论】:

    • 好的,谢谢。所以“真正的嵌套查询”在 MongoDB 中是不可能的?是的,我同意你关于 ObjectIds 的评论,但我只是在这个例子中使用了字符串来保持简单。
    • 对,没有嵌套查询,您的数据需要结构化,以便您可以通过对数据库的单个(或最少数量)请求获得所需的内容。
    【解决方案2】:

    定义函数

    function bbb(){
        var org_ids = new Array();
        var orgs = 
            db.orgTreeNode.find({ancestors:"ca5cd344-ba47-4601-a07b-ea2c684bfb4e"},{"_id":1});
        orgs.forEach(function(org){
            org_ids.push(org._id);
        })
    
        return db.user.find({"org":{$in:org_ids}}).skip(300).limit(10);
    }
    

    执行函数

    bbb()
    

    【讨论】:

    • 这应该是公认的答案。它仅在 2 db 调用中回答嵌套查询的问题,而不是 O(NxN)。谢谢@pippo
    【解决方案3】:

    如果它可以触发得到你的答案--

    db.users.find({
        _id: {
            $in: db.logs.find({
                loggedbyuser: {
                    $ne: ObjectId("569f9d093447ee781ca80b52")
                },
                logtype: "marketfetched",
                "logcreated": {
                    $gt: new ISODate("2016-02-06T00:00:00.871Z")
                }
            }, {
                loggedbyuser: 1,
                _id: 0
            }).sort({
                'logcreated': -1
            }).map(function(like) {
                return like.loggedbyuser;
            })
        }
    }).map(function(like) {
        return like.fullname;
    });
    

    【讨论】:

    • 该操作要求一个类似于 SQL 的嵌套查询,该查询仅在数据库中执行一个步骤。您只是获取“嵌套”查询的结果,然后再次通过网络发送。
    【解决方案4】:

    -确定

    SQL 查询:(分组方式和不同计数)

    select city,count(distinct(emailId)) from TransactionDetails group by city;
    

    等效的 mongo 查询如下所示:

    db.TransactionDetails.aggregate([ 
    {$group:{_id:{"CITY" : "$cityName"},uniqueCount: {$addToSet: "$emailId"}}},
    {$project:{"CITY":1,uniqueCustomerCount:{$size:"$uniqueCount"}} } 
    ]);
    

    【讨论】:

      【解决方案5】:
      db.usergroup.aggregate([
        { $match: { _id: "g1" } }, 
        { $unwind: "$Users" }, 
        { $lookup: 
          { from: "user", localField: "Users", foreignField: "_id", as: "user" } 
        } 
      ])
      
      // result :
      { "_id" : "g1", "Users" : "u2", "user" : [ { "_id" : "u2", "Name" : "u1 name" } ] }
      { "_id" : "g1", "Users" : "u3", "user" : [ { "_id" : "u3", "Name" : "u3 name" } ] }
      
      

      【讨论】:

        【解决方案6】:

        我对 mongodb 中的嵌套查询也有同样的疑惑。就我而言,我稍微放了一点,让它工作,我认为你的也可以通过使用“$ or”并使用 toArray()

        db.user.find({$or:db.usergroup.find({_id:"g1"},{_id:0,Users:1}).toArray()})
        

        可能不太正确,但这是我的数据使用下一个查询的示例。显然有点傻,为什么在这种情况下将 id 反馈回另一个查询,但想看看它是否会起作用并且确实有效:

        db.notification.find({$or:db.notification.find({'startDate': { '$gte': ISODate("2019-08-01") }},{_id:1}).limit(10).toArray()})
        

        【讨论】:

          猜你喜欢
          • 2022-11-03
          • 1970-01-01
          • 1970-01-01
          • 2019-02-28
          • 2014-07-23
          • 1970-01-01
          • 2019-05-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多