Фильтровать нулевые значения двух популяций в Mongoose - PullRequest
1 голос
/ 23 апреля 2020

ОСНОВНАЯ ЦЕЛЬ

Я хочу получить переводы, которые проецируются как термины (Term) с одним отношением (Relation) между ними.

СТАТУС

Я описываю термины Term. Думайте об этом как слова (обычно существительные).

const TermSchema: Schema = new Schema({
  _id:  mongoose.Schema.Types.ObjectId,  
  term: { type: String, required: true },
  lang: { type: String, required: true},
  relations: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Relation' }],
});

export default mongoose.model<Term & mongoose.Document>('Term', TermSchema);

Схема Relation описывает отношения этих терминов.

const RelationSchema: Schema = new Schema({
    _id:  mongoose.Schema.Types.ObjectId,  
    relationType: { type: String, required: true, default: RelationEnum.TRANSLATION },
    termSrc: { type: mongoose.Schema.Types.ObjectId, ref: 'Term'  },
    termTrg: { type: mongoose.Schema.Types.ObjectId, ref: 'Term'  },    
  });

export default mongoose.model<Relation & mongoose.Document>('Relation', RelationSchema);

Я хочу получить все переводы из языковой комбинации , Допустим, немецкий (de) и арабский c (ar). То есть:

  1. Извлечь все отношения с relationType значения RelationEnum.TRANSLATION.
  2. Заполнить termSr c, где язык является либо de, либо ar.
  3. Заполните termTrg, где язык является либо de, либо ar.

, что привело меня к написанию следующего выражения mon goose.

var query = Relation.find({relationType: 'TRANSLATION' }, null)
                .populate( {path: 'termSrc', select: 'term lang', model: Term, match: {lang: {$in: ['ar', 'de']}}})
                .populate( {path: 'termTrg', select: 'term lang', model: Term, match: {lang: {$in: ['ar', 'de']}}});

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

    {
        "_id": "41224d776a326fb40f000023",
        "relationStatus": "QUALIFIED",
        "termSrc": {
            "_id": "41224d776a326fb40f000021",
            "term": "Verhaftung",
            "lang": "de"
        },
        "termTrg": {
            "_id": "41224d776a326fb40f000022",
            "term": "اعتقالات",
            "lang": "ar"
        }
    }

ПОСТАНОВКА ЗАДАЧИ

Поскольку совокупность termSr c и termTrg полностью независимы (это как оператор ИЛИ, дизъюнкция), он также будет включать отношения, в которых к совокупности применяется только один фильтр. Таким образом, запрос также вернет записи для переводов на французский-арабский c. Конечно, установив для термина fr значение null (потому что мы ищем 'ar', 'de'), как в этом примере записи.

   {
        "_id": "01224d776a326fb40f000050",
        "relationStatus": "QUALIFIED",
        "termSrc": null,
        "termTrg": {
            "_id": "01224d776a326fb40f000034",
            "term": "تقالا",
            "lang": "ar"
        }
    }

Это не то, что я хочу, и приводит к очистке после математики. Я хочу только переводы de-ar и ar-de.

Поскольку моя главная цель выражается, я хотел бы, чтобы возвращались только отношения, где заполнены ОБА термины (ни один из них не должен быть null).

  • Можно ли 1) запустить find, затем оба populate, а затем 2) запустить фильтр для промежуточного результата, чтобы избежать null записей?
  • Если это невозможно Выполнение промежуточных запросов, как можно достичь этого с помощью агрегатов, отсюда и отфильтровать все отношения с нулевыми записями в termSr c и termTrg?

1 Ответ

1 голос
/ 23 апреля 2020

Вы можете использовать ниже $lookup версия

  Relation.aggregate([
    { $match: { relationType: "TRANSLATION" } },
    {
      $lookup: {
        from: Term.collection.name,
        let: { termSrc: "$termSrc" },
        pipeline: [{ $match: { $expr: { $eq: ["$_id", "$$termSrc"] } } }],
        as: "termSrc"
      }
    },
    { $unwind: "$termSrc" },
    {
      $lookup: {
        from: Term.collection.name,
        let: { termTrg: "$termTrg" },
        pipeline: [{ $match: { $expr: { $eq: ["$_id", "$$termTrg"] } } }],
        as: "termTrg"
      }
    },
    { $unwind: "$termTrg" }
  ]);
...