2016-07-30 4 views
0

Я застрял в запросе MongoDB. У меня есть простая структура для управления потоками и сообщениями в моем приложении.Запросить непрочитанные сообщения

{ 
    participants: [ 
    'u1,'u2' 
    ] 
    messages: [ 
    {text: 'some message', readBy: ['u1','u2']} 
    {text: 'some other message', readBy: ['u1']} 
    ] 
} 

Будучи «u2» Я хотел бы получить эту конкретную нить, возвращаемой запросом. Вот как далеко я пришел, но как только одно сообщение было прочитано 'u2', оно больше не возвращается, поскольку одно из сообщений было прочитано 'u2'.

Threads.find(
     { 
      $and: [ 
       {'participants': this.userId}, 
       {'messages.readBy': {$nin: [this.userId]}}   
      ] 
     }    
    ) 

Как я могу достичь этого, не меняя свою структуру данных?

+0

Что такое ожидаемое результат вашего запроса? – styvane

+0

В конце концов мне нужно, чтобы он подсчитывал все непрочитанные потоки, т. Е. Был выбран любой поток, имеющий хотя бы 1 непрочитанное сообщение. Я буду использовать эту информацию для отображения значка на веб-странице, чтобы пользователь знал, что есть непрочитанные сообщения. Исходя из SQL, я не использовал для хранения денормализованных материалов, поэтому я оказался с данной структурой. Важно отметить, что я использую Meteor, поэтому не все MongoDB поддерживает работы из коробки и является реактивным. – chris1069603

+0

Если ответ, который вы приняли, работал, тогда есть лучший способ сделать это. – styvane

ответ

0

Вы можете использовать команду aggregation, чтобы выполнить операцию $unwind, которая преобразует массив messages в объект Json, который поможет вам запросить именно тот предмет, который вам нужен.

Следующий запрос даст вам записи, где «u2» которых участвует только сообщения не читаются «u2»:

db.threads.aggregate([{ 
    $unwind: "$messages" 
}, { 
    $match: { 
     "participants": "u2", 
     "messages.readBy": { 
      $nin: ["u2"] 
     } 
    } 
}]); 

это даст вам:

{ 
    "_id": ObjectId("579d0fc8733ac30906524be4"), 
    "participants": ["u1", "u2"], 
    "messages": { 
     "text": "some other message", 
     "readBy": ["u1"] 
    } 
} 
+0

Должен признаться, что раньше я никогда не использовал скопления. Большое спасибо за компетентный ответ. Я попросил не изменять структуру данных, но отрицание readBy (т. Е. Использование unreadBy) позволило бы использовать обычный запрос, насколько я понял? Вы бы рекомендовали использовать агрегацию или, как правило, лучше изменить структуру данных, чтобы я мог использовать обычный запрос? – chris1069603

+0

это зависит от вас. Если вы используете запрос 'find', вам придется анализировать результат в соответствии с вашими предпочтениями, тогда как при использовании агрегатов двигатель mongoDB сделает это за вас. агрегация займет немного больше времени, но вы можете группировать, создавать поле, проект и т. д.. Учтите, что с агрегацией вы можете иметь один массив со всем новым сообщением непрочитанным, тогда как с помощью 'find' вам придется перебирать результат и построить этот массив самостоятельно –