Как сделать вложенные запросы в MongoDb, который работает как вложенные запросы выбора Sql

Я хочу сделать эффективный запрос в MongoDb, чтобы найти всех пользователей, у которых есть свои пользователи, перечисленные в группе пользователей. В идеале я хочу сделать это как единый запрос к Mongodb. То, что я хочу, соответствует вложенным выборам в SQL. Я пробовал это в оболочке mongo:

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

Теперь вот выбор, который я хочу сделать, но без hardcoding массив [ "u2", "u3" ]:

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

Это отлично работает и возвращает пользовательские объекты для u2 и u3.

Теперь вопрос заключается в том, как получить массив идентификаторов пользователя в операторе $in, извлеченном с помощью запроса, чтобы весь запрос мог быть сделан с помощью одного запроса.

"Вложенный запрос" вроде этого не работает:

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

Дает эту ошибку:   Tue Mar 27 06:17:41 uncaught exception: error: { "$ err": "invalid query", "code": 12580}   не удалось загрузить: mongoNestedSelect.js

1) это возможно в mongodb и как?

2) как это сделать с официальным драйвером С#?

Ответ 1

Ответ на такие вопросы в MongoDB часто заключается в денормализации ваших данных. Если вам нужен только список пользователей в группе, вы можете сохранить идентификатор пользователя и имя пользователя в документе группы. В некотором роде вы структурируете свою базу данных в соответствии с результатом, который хотите видеть на экране, а не пытаться поместить его в какой-то нормализованный формат.

Очевидно, что это будет работать только в том случае, если ваш список групп пользователей (с именами) может поместиться в один документ, но ваш текущий подход также имеет некоторые ограничения относительно максимального размера группы.

Другим подходом было бы хранение групп, к которым принадлежит пользователь в массиве, в каждом документе "Пользователь". Добавьте индекс в это поле массива, и теперь вы можете найти пользователей по группам. Учитывая, что пользователь, вероятно, будет принадлежать меньшим группам, чем есть члены в группе, это может быть лучшим подходом здесь.

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

Снова вы можете сохранить имя группы со своим _id, чтобы сразу отобразить список групп, к которым принадлежит пользователь, с одним раундом. Конечно, если вы позволите изменить имя группы, вам нужно будет запустить фоновое задание, чтобы исправить все эти копии имени.

Я бы также использовал встроенный генератор id MongoDB, а не свой собственный, он имеет много желаемых свойств.

Ответ 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()

Ответ 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;
});

Ответ 4

-sUReN

SQL Query: (по группам и количеству отдельных)

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

Мне было интересно то же самое о вложенных запросах в mongodb. Для моего случая я немного положил и заставил его работать, и я думаю, что ваш тоже будет с помощью "$ или" и использовать toArray()

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

Может быть, это не совсем верно, но это пример моих данных, которые работали с использованием следующего запроса. Очевидно, немного глупо, почему в этом случае возвращать идентификаторы в другой запрос, но хотел посмотреть, сработает ли он, и он это сделал:

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