MongoDB: find и findOne с фильтрацией вложенных массивов

Эта маленькая задача оказалась сложнее, чем я думал.

Рассмотрим следующую очень простую коллекцию сообщений. Предположим, я хочу отобразить все сообщения в сочетании только с теми комментариями, которые не были удалены.

IE отфильтровывает удаленные комментарии из массива комментариев.

Поскольку у меня есть 100 удаленных комментариев на пост, есть ли способ сделать это на стороне сервера?

Коллекция:

{
  "author": {},
  "message": "This is post1",
  "comments": [
    {
      "message": "Im number 1!!!",
      "state": {
        "deleted": false
      }
    },
    {
      "message": "YOU MOTHERF****R",
      "state": {
        "deleted": true
      }
    },
    {
      "message": "tHIS IS GREAT!",
      "state": {
        "deleted": false
      }
    },
    {
      "message": "I can type better than you guys",
      "state": {
        "deleted": false
      }
    }
  ]
},
{
  "author": {},
  "message": "This is post 2",
  "comments": [
    {
      "message": "This is bulls**t",
      "state": {
        "deleted": true
      }
    },
    {
      "message": "YOU MOTHERF****R",
      "state": {
        "deleted": true
      }
    },
    {
      "message": "I hate u!",
      "state": {
        "deleted": true
      }
    },
    {
      "message": "I wanna have your children",
      "state": {
        "deleted": false
      }
    }
  ]
}

1 ответ

Решение

Я буду TL;DR, поскольку это оказалось адской поездкой. я пробовал $elemMatch, Я пробовал $redact (также с $$CURRENT и $$ROOT), я попробовал $mapЯ пробовал структуру агрегации, я пробовал $project,

Вы можете прочитать все об этом здесь: https://www.devsbedevin.com/mongodb-find-findone-with-nested-array-filtering-finally/

TL;DR

Похоже, что решение состоит в том, чтобы использовать структуру агрегации для фильтрации массива и переопределить свойство comments результатами. Это проще, чем кажется:

db.getCollection('posts').aggregate(
    {$match: {"author.id": authorId}},
    {$addFields : {"comments":{$filter:{ // We override the existing field!
        input: "$comments",
        as: "comment",
        cond: {$eq: ["$$comment.state.deleted", false]}
    }}}}
);

Результат:

{
  "author": {},
  "message": "This is post1",
  "comments": [
    {
      "message": "Im number 1!!!",
      "state": {
        "deleted": false
      }
    },
    {
      "message": "tHIS IS GREAT!",
      "state": {
        "deleted": false
      }
    },
    {
      "message": "I can type better than you guys",
      "state": {
        "deleted": false
      }
    }
  ]
},
{
  "author": {},
  "message": "This is post 2",
  "comments": [
    {
      "message": "I wanna have your children",
      "state": {
        "deleted": false
      }
    }
  ]
}
Другие вопросы по тегам