НЕОЖИДАННЫЙ вопрос.
Мне прям невмоготу как надо сделать join. Что то ничего полезного по теме не могу найти без лишних подключаемых модулей.
Задача: достать список друзей и групп одним api-вызовом.
Что имеем:
- 3 коллекции:
users - пользователи (требуемые поля _id, first_name, last_name)
friends - список друзей каждого пользователя (что то типа связывающей таблицы многие-ко-многим, содержит поля group_id, owner и friend, где group_id - _id группы в которую пользователь запихнул этого друга, owner - _id самого пользователя-владельца, friend - _id друга (по сути - _id другого пользователя))
groups - список групп
В общем виде вот так выглядят записи в этих хранилищах:
Users:
{
"_id" : ObjectId("56263bd1bc9082875487820b"),
"first_name" : "Вячеслав",
"last_ip" : "",
"last_name" : "Дядчиков",
"online" : 1,
"online_date" : ISODate("2015-10-21T07:49:30.93Z"),
"register_date" : ISODate("2015-10-20T13:04:17.814Z"),
"sex" : 1,
"state" : 2
}
Friends:
{
"owner" : ObjectId("56263bd1bc9082875487820b"),
"friend" : ObjectId("562743368a654b61739a7b27"),
"group_id" : 1,
"state" : 1,
"add_date" : ISODate("2015-10-21T11:43:17.498Z"),
"_id" : ObjectId("56277a55f472bd707e67f2d7")
}
Groups:
{
"_id" : 1,
"name" : "Без группы",
"owner" : 0,
"state" : 1,
"add_date" : ""
}
Достать список групп - легко.
Достать просто список друзей (чисто список _id друзей) - легко.
Достать расширенный список друзей - что то никак не получается. Ну, точнее получается, но... Сейчас опишу ситуацию.
Достать всё это сразу и отправить пользователю - вообще никак не получается.
Клиент делает вызов api "блаблабла/friends.get". Передаётся _id пользователя запрашивающего список. Должен вернуться JSON содержащий массив friends (одна запись содержит поля _id,first_name,last_name,group_id) и массив groups (одна запись содержит поля _id, name).
Соответственно как я вижу решение:
1) Берём из коллекции friends нужные записи по owner, и по этим записям берём из коллекции users данные (first_name, last_name).
2) Берём из коллекции groups нужные записи по owner
3) формируем JSON и отправляем в ответ на вызов API
На какие проблемы я наткнулся:
1) не пойму как вызывать функции ПОСЛЕДОВАТЕЛЬНО, т.е.
что бы функция поиска групп вызвалась сразу после окончания поиска друзей.
Сделал так:
db.collection('friends').find({owner:id,state:{$gt:0}}).toArray(friendCallback);
db.collection('groups').find({state:{$gt:0},$or:[{owner:id},{owner:0}]}).toArray(groupCallback);
res.end(JSON.stringify({
data: [{
type: 0,
code: 0,
friends: friends,
groups: groups
}],
error: null
}));
Но, оно выполняется сразу, вызывается сначала поиск в друзьях, потом не дожидаясь отрабатывания коллбэка вызывается поиск в группах, и , не дожидаясь отрабатывания коллбэка отправляется ответ.
Пытался делать выхов в коллбэке, тогда работает, но код выглядит просто ужасно (ещё ужаснее чем сейчас).
2) связанно с первым, так как в функции
friendCallback я делаю ещё один запрос для раширенных данных:
function friendCallback(err, results){
for (var i = 0; i < results.length; i++) {
db.collection('users').find({_id:new ObjectID(results[i].friend)}).toArray(friendCallback1);
}
}
И оно конечно же тоже не успевая отрабатывать перелетает по циклу, а ведь в friendCallback1 как раз происходит формирования массива friends, который потом отдаётся в ответ.
Сейчас в результате всего этого дела пользователю приходит ответ с пустыми массивами.
{"data":[{"type":0,"code":0,"friends":[],"groups":[]}],"error":null}
На SQL такое решается элементарным join:
SELECT u.id,
u.firstName,
u.lastName,
f.f_groupId
FROM users AS u
LEFT JOIN friends as f ON f.friend = u.id
WHERE f.state = 1 AND f.owner = ?
Поиск вменяемого ответа не дал, да хотя я и ищу скорее всего не правильно (потому что ищу что то в стиле "как сделать join в node.js+mongodb"). Могу это реализовать тремя разными вызовами API (написав их, конечно же), но надо что бы всё прилетало в одном вызове.
зыЖ наверно это выглядит как тупое клянчанье "напишите за меня код", но нет, код не прошу. Прошу теорию, которую я, увы, не знаю.