问题 如何在MongoDb中创建嵌套查询,就像嵌套的Sql选择查询一样


我想在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运算符中的userid数组,以便可以使用单个请求创建整个查询。

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

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

给出了这个错误:     Tue Mar 27 06:17:41未捕获的异常:错误:{“$ err”:“无效查询”,“代码”:12580}     无法加载:mongoNestedSelect.js

1)这可能在mongodb中如何?

2)如何使用官方c#驱动程序执行此操作?


2818
2018-03-27 05:03


起源



答案:


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

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

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

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

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

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


6
2018-03-27 05:51



好,谢谢。那么“真正的嵌套查询”在MongoDB中是不可能的?是的,我同意你对ObjectIds的评论,但我只是在这个例子中使用字符串来保持简单。 - ssn
没错,没有嵌套查询,您的数据需要进行结构化,以便您可以通过单个(或最小数量)的数据库请求获得所需的数据。 - Ian Mercer


答案:


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

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

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

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

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

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


6
2018-03-27 05:51



好,谢谢。那么“真正的嵌套查询”在MongoDB中是不可能的?是的,我同意你对ObjectIds的评论,但我只是在这个例子中使用字符串来保持简单。 - ssn
没错,没有嵌套查询,您的数据需要进行结构化,以便您可以通过单个(或最小数量)的数据库请求获得所需的数据。 - Ian Mercer


定义功能

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()

7
2017-08-10 05:58





如果它可以触发让你 -

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;
});

1
2018-02-07 02:54



op要求一个类似于SQL的嵌套查询,它只在DB内部执行一步。您只是获取“嵌套”查询的结果,并再次通过网络发送它。 - Leandro Glossman


-sUReN

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"}} } 
]);

1
2018-02-22 09:58