Как сделать вложенные запросы в MongoDb, которые работают как вложенные запросы выбора SQL - PullRequest
13 голосов
/ 27 марта 2012

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

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, извлеченный с помощью запроса, чтобы весь запрос мог быть выполнен с помощью одного запроса.

Такой «вложенный запрос» не работает:

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

Дает эту ошибку: Вт 27 марта 06:17:41 необработанное исключение: ошибка: {"$ err": "неверный запрос", "код": 12580} не удалось загрузить: mongoNestedSelect.js

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

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

Ответы [ 4 ]

7 голосов
/ 10 августа 2012

определить функцию

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 голосов
/ 27 марта 2012

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

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

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

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

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

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

1 голос
/ 22 февраля 2017

-sUReN

SQL-запрос: (группировка по количеству различных элементов)

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

Эквивалентный запрос монго будет выглядеть так:

db.TransactionDetails.aggregate([ 
{$group:{_id:{"CITY" : "$cityName"},uniqueCount: {$addToSet: "$emailId"}}},
{$project:{"CITY":1,uniqueCustomerCount:{$size:"$uniqueCount"}} } 
]);
1 голос
/ 07 февраля 2016

Если это может сработать, чтобы получить ответ ...

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