2013-04-09 3 views
0

у меня есть коллекция messages со следующими документамиQuery сгруппированы по двум своп полей

{ 
    "_id" : ObjectId("5164218f359f109fd4000012"), 
    "receiver_id" : ObjectId("5164211e359f109fd4000004"), 
    "sender_id" : ObjectId("5162de8a359f10cbf700000c"), 
    "body" : "Hello Billy!!!", 
    "readed" : false, 
    "updated_at" : ISODate("2013-04-09T14:11:27.17Z"), 
    "created_at" : ISODate("2013-04-09T14:11:27.17Z") 
} 

Мне нужно сделать запрос на получение последних сообщений (не имеет значения получили или отослано) для данного пользователя (сгруппированные по reciever_id + sender_id) и отсортированы по created_at.

Чтобы лучше объяснить вопрос, пример того, как я сделал это в SQL:

SELECT DISTINCT ON (sender_id+receiver_id) * FROM messages 
    ORDER by (sender_id+receiver_id), created_at DESC 
    WHERE sender_id = given_user or receiver_id = given_user 

Я не понимаю, как решить эту проблему с mondodb.

ответ

1

Не существует явного способа сделать это. Давайте рассмотрим обходные пути:

Путь 1: сделать внятного на уровне кода (после находки), а затем просто использовать find:

db.message.find({$or:[{sender_id:?}, {receiver_id:?}]}) 

Способ 2: Использование основы агрегации:

db.message.aggregate([ 
    {$match: {$or:[{sender_id:?}, {receiver_id:?}]}, 
    $group: { _id: {sender:"$sender_id", receiver:"$receiver_id"}, 
       other: { ... } } }, 
    $sort: {sender_id,receiver_id,...} 
    ]) 

Этот так как sender_id, receiver_id - это не то же самое, что и sender_id+receiver_id

Wa y 3: Введите суррогатное поле sender_id + receiver_id, затем используйте find или даже distinct за подсказку Стенни.

+0

С помощью вашего пути № 3 и суррогатного поля вы можете использовать команду [distinct()] (http://docs.mongodb.org/manual/reference/command/distinct/) в этом поле вместо 'найти()'. – Stennie

+0

Путь № 2 с '$ group: {_id: {sender:" $ sender_id ", получатель:" $ receiver_id "}}' кажется, не работает, потому что когда поля меняются, это делает новый объект в результате. – ole

+0

@Stennie - вы правы, просто исправьте – Dewfy

2

Aggregation Framework в MongoDB 2.2+ обеспечивает наиболее очевидный перевод вашего запроса. Руководство MongoDB содержит SQL to Aggregation Framework Mapping Chart в качестве общего руководства, хотя существуют определенные различия в двух подходах.

Вот пример с комментариями вы можете попробовать в mongo оболочки: результат

var given_user = ObjectId("5162de8a359f10cbf700000c"); 
db.messages.aggregate(
    // match: WHERE sender_id = given_user or receiver_id = given_user 
    // NB: do the match first, because it can take advantage of an available index 
    { $match: { 
     $or:[ 
      { sender_id: given_user }, 
      { receiver_id: given_user }, 
     ] 
    }}, 

    { $group: { 
     // DISTINCT ON (sender_id+receiver_id) 
     _id: { sender_id: "$sender_id", receiver_id: "$receiver_id" } 
    }}, 

    // ORDER by (sender_id+receiver_id), created_at DESC 
    { $sort: { 
     sender_id: 1, 
     receiver_id: 1, 
     created_at: -1 
    }} 
) 

Пример:

{ 
    "result" : [ 
     { 
      "_id" : { 
       "sender_id" : ObjectId("5162de8a359f10cbf700000c"), 
       "receiver_id" : ObjectId("5164211e359f109fd4000004") 
      } 
     } 
    ], 
    "ok" : 1 
} 

Вы можете добавить дополнительные поля на группировки, такие как подсчет сообщений получено.

Если вы действительно хотите объединить sender_id + receiver_id в одно поле, вы можете использовать оператор $concat в MongoDB 2.4+.

+0

In ситуация, когда given_user не просто отправляется, но и получает некоторые сообщения. Группа не работает по мере необходимости, потому что поля (sender_id, receiver_id) для данного_пользователя сменили, и этот рождаемый новый объект в результате. – ole

+0

По этой причине я использовал 'sender_id + receiver_id' в SQL. – ole

+0

Если вы соответствуете данному_сумеру как 'sender_id' или' receiver_id', это будет охватывать случай этого пользователя, отправляющего или получающего сообщения, и должен быть эквивалентен вашему SQL-запросу.Сгруппированный вывод будет отличаться от случая, когда те же самые два пользователя обмениваются сообщениями электронной почты: '{sender_id: user1, receiver_id: user2}' vs '{sender_id: user2, receiver_id: user1}. Если вам действительно нужны уникальные пары, ваш SQL-запрос также должен быть изменен. – Stennie

Смежные вопросы