MongoDB Получить подмножество массива в коллекции, указав два поля, которые должны совпадать - PullRequest
0 голосов
/ 08 февраля 2012

Я использую эту структуру для хранения разговоров и сообщений:

{ "_id" : ObjectId( "4f2952d7ff4b3c36d700000d" ),
"messages" : [ 
  { "_id" : ObjectId( "4f2952d7ff4b3c36d700000c" ),
    "sender" : "4f02f16f0364c024678c0e5f",
    "receiver" : "4f02f16f0364c024678c0e61",
    "receiver_deleted" : "true",
    "sender_deleted" : "true",
    "body" : "MSG 1",
    "timestamp" : "2012-02-01T14:57:27Z" }, 
  { "_id" : ObjectId( "4f2952daff4b3c36d700000e" ),
    "sender" : "4f02f16f0364c024678c0e61",
    "receiver" : "4f02f16f0364c024678c0e5f",
    "body" : "MSG 2",
    "timestamp" : "2012-02-01T14:57:30Z" }, 
  { "_id" : ObjectId( "4f295305ff4b3c36d700000f" ),
    "sender" : "4f02f16f0364c024678c0e5f",
    "receiver" : "4f02f16f0364c024678c0e61",
    "body" : "TEST",
    "timestamp" : "2012-02-01T14:58:13Z" } ],
"participants" : [ 
  "4f02f16f0364c024678c0e5f", 
  "4f02f16f0364c024678c0e61" ],
"type" : "chat" }

Когда один из отправителей или получателей действительно удаляет определенное сообщение, к сообщению добавляется receive_deleted или sender_deleted (как вы видите впервое сообщение).

Теперь, как я могу получить беседу только с сообщениями, в которых не установлен флаг удаления отправителя / получателя?

Сначала я попробовал вот так:

db.conversations.find({
  "_id": ObjectId("4f2952d7ff4b3c36d700000d"),
  "participants": {"$in": ["4f02f16f0364c024678c0e5f"]},
  "$or": [
    {
      "$and": [{"messages.sender": "4f02f16f0364c024678c0e5f"}, {"messages.sender_deleted": {"$exists": false}}]
    },
    {
      "$and": [{"messages.receiver": "4f02f16f0364c024678c0e5f"}, {"messages.receiver_deleted": {"$exists": false}}]
    }
  ]
})

Но это не работает.Я также пытался использовать $ elemMatch следующим образом:

db.conversations.find({
  "_id": ObjectId("4f2952d7ff4b3c36d700000d"),
  "participants": {"$in": ["4f02f16f0364c024678c0e5f"]},
  "$or": [
    {
      "messages": {
        "$elemMatch": {"sender": "4f02f16f0364c024678c0e5f", "sender_deleted": {"$exists": False}}
      }
    },
    {
      "messages": {
        "$elemMatch": {"receiver": "4f02f16f0364c024678c0e5f", "receiver_deleted": {"$exists": False}}
      }
    }
  ]
})

И пару других вариантов с попыткой $, а не $ или т. Д., Но это не работает .. Либо ничего не возвращает, либо весь разговорнезависимо от получателя / отправителя удаленные поля.

Спасибо, Михаил

Ответы [ 2 ]

2 голосов
/ 08 февраля 2012

В настоящее время невозможно получить подмножество массива с помощью mongodb.Вы всегда получите весь документ обратно, если есть совпадение, или ничего, если нет совпадения.$ slice позволяет вам возвращать подмножество, но оно основано на индексе запуска и остановки (это не то, что вы хотите - так как вы хотите вернуть только совпадающие сообщения в массиве).

Функция, которой вы являетесьописание было зарегистрировано и запрошено здесь: https://jira.mongodb.org/browse/SERVER-828

1 голос
/ 22 ноября 2013

Начиная с версии 2.2 Доступна структура агрегации .Вы можете выполнить свой запрос следующим образом:

db.expose.aggregate(    
//Find the Documents which contains the desired criteria (document level)
{
  $match: {
    $or: [
      {
        "messages.sender_deleted": "true"
      },
      {
        "messages.receiver_deleted": "true"
      }]}},
//Peels off the elements of messages array individually
{
  $unwind: "$messages"
},
//Perform the same find method, now in the embed collection level
{
  $match: {
    $or: [
      {
        "messages.sender_deleted": "true"
      },
      {
        "messages.receiver_deleted": "true"
      }]}},
//Select what to show as the result: in this case the Document id and the messages array
{
  $group: {
    _id: "$_id",
    messages: {
      $push: "$messages"
    }}});

Первое совпадение не требуется, но лучше отфильтровать как можно больше в начале.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...