Как сделать вложенные запросы в 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()})