Монго-фильтрация с глубоко вложенными массивами - PullRequest
0 голосов
/ 28 января 2019

У меня есть документы, которые выглядят так:

{
  {
    "id": "5c4a208bbddbb7c2ae231584",
    "sections": [
      {
        "id": "5c4a208bbddbb7c2ae231576",
        "subsections": [
          {
            "isReviewed": true,
            "flags": {
              "types": [
                "UNORIGINAL",
                "SIMILAR"
              ],
              "predicted": [
                "UNORIGINAL",
                "SIMILAR"
              ]
            }
          }
        ]
      }
    ]
  }

  {
    "id": "5c4a208bbddbb7c2ae231585",
    "sections": [
      {
        "id": "5c4a208bbddbb7c2ae231580",
        "subsections": [
          {
            "isReviewed": false,
            "flags": {
              "types": [
                "SIMILAR"
              ],
              "predicted": []
            }
          }
        ]
      }
    ]
  }
}

С этим документом я хочу вычислить статус каждого документа, используя комбинацию его поля isReviewed и его subsections. * 1006.*

Документом является

  • STATUS_REVIEWED, если все его подразделов, которые имеют элементы в predicted, равны isReviewed = true
  • STATUS_PARTIAL, если некоторые его подразделов, которые содержат элементы в predicted, равны isReviewed = true
  • STATUS_UNREVIEWED, если все его подразделов, которые имеютэлементы в predicted равны isReviewed = false
  • STATUS_IRRELEVANT, если ни один из его подразделов не содержит элементов в predicted

Правильный результат с этими данными будет выглядеть следующим образом:

Желаемый результат

[
  {
    "id": "5c4a208bbddbb7c2ae231584",
    // All of its subsections are reviewed and has items in predicted
    "reviewStatus": ["STATUS_REVIEWED"]
  },
    "id": "5c4a208bbddbb7c2ae231585",
    // All of its subsections do not have any items in predicted
    "reviewStatus": ["STATUS_IRRELEVANT"]
  },
] 

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

  Item.aggregate()
    .match({ _id: { $in: ids } })
    .project({ a: '$sections.subsections' })
    .unwind('$a')
    .unwind('$a')
    .project({
      isReviewed: '$a.isReviewed',
      hasPredictions: { $gt: [{ $size: '$a.flags.predicted' }, 0] }
    })
    .match({ hasPredictions: true })
    .group({ _id: '$_id', reviewStatuses: { $addToSet: '$isReviewed' } })
    .group({
      _id: '$_id',
      reviewStatus: {
        $push: {
          $switch: {
            branches: [
              {
                case: {
                  $and: [
                    { $in: [false, '$reviewStatuses'] },
                    { $in: [true, '$reviewStatuses'] },
                  ]
                },
                then: 'STATUS_PARTIAL'
              },
              {
                case: {
                  $eq: [[true], '$reviewStatuses']
                },
                then: 'STATUS_REVIEWED'
              },
              {
                case: {
                  $eq: [[false], '$reviewStatuses']
                },
                then: 'STATUS_UNREVIEWED'
              }
            ],
            default: 'STATUS_UNKNOWN'
          }
        }
      }
    })
    // Post processing
    .then((items) => {
      const itemsById = _.keyBy(items, '_id');
      return itemIds.map((itemId) => {
        const status = itemsById[itemId];
        // Set to STATUS_IRRELEVANT item is not in result
        if (status === undefined) return 'STATUS_IRRELEVANT';
        return status.reviewStatus[0];
      });
    })

Этот запрос прекрасно работает, но если в документе нет подразделов с элементами в predicted, шаг сопоставления будет пропущендокумент из результата и потребует от меня последующей обработки, чтобы проверить, есть ли документ в результате (а затем добавить 'STATUS_IRRELEVANT').

Что я получу

[
  {
    "id": "5c4a208bbddbb7c2ae231584",
    // All of its subsections are reviewed and items in predicted
    "reviewStatus": ["STATUS_REVIEWED"]
  }
  // Doc "5c4a208bbddbb7c2ae231585" is missing here because of the match
] 

Как мне переписать этот запрос, чтобы получить желаемый результат?

...