Показать сообщение отдельно
Старый 21.10.2015, 17:33   #19
St_AnGer
Элита
 
Аватар для St_AnGer
 
Регистрация: 21.01.2010
Адрес: Россия, Рязанская область, г.Михайлов
Сообщений: 2,067
Написано 1,185 полезных сообщений
(для 2,828 пользователей)
Ответ: Чат: PHP + MySQLi или что то другое?

НЕОЖИДАННЫЙ вопрос.

Мне прям невмоготу как надо сделать 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 (написав их, конечно же), но надо что бы всё прилетало в одном вызове.

зыЖ наверно это выглядит как тупое клянчанье "напишите за меня код", но нет, код не прошу. Прошу теорию, которую я, увы, не знаю.
__________________
Main PC:
Intel Core i5 4260U 1.44 GHz + LPDDR3 1x4096 1600 MHz + Intel HD Graphics 5000.

Asus Ёжик T101-MT:
Intel Atom N-570 1.66 Ghz + DDR2 2x1024 800 Mhz + Intel GMA 3150 128 Mb DDR2


Скачать Doom 2D: Remake v0.3.8a

Последний раз редактировалось St_AnGer, 22.10.2015 в 00:45.
(Offline)
 
Ответить с цитированием