Несколько условий с агрегацией $ lookup - PullRequest
0 голосов
/ 01 декабря 2018

Я рассматриваю использование передового опыта для решения следующей проблемы с Mongoose.

У меня есть три схемы:

const SchemaA = new Schema({
  name: String
});

const SchemaB = new Schema({
  schemaA: {
    type: Schema.Types.ObjectId,
    ref: 'SchemaA',
    required: true
  }
});

const SchemaC = new Schema({
  schemaB: {
    type: Schema.Types.ObjectId,
    ref: 'SchemaB'
  },
  user: {
    type: Schema.Types.ObjectId,
    ref: 'User'
  }
});

Мне нужно получить объекты schemaB по идентификатору schemaA с schemaCприсоединен, но отфильтрован пользователем.

getSchemaBs: async (schemaAId, userId) => {
  try {
    SchemaB.find({ schemaA: schemaAId }).populate('schemaC': where user === userId);
  } catch (e) {
    throw new Error('An error occurred while getting schemasB for specified schemaA.');
  };

Я занимаюсь рефакторингом кода, написанного с использованием собственного драйвера Mongo для NodeJS.Теперь я хочу упростить использование Mongoose.

Более ранняя версия кода (имейте в виду, что она не может следовать передовым методам):

getList: function (schemaAId, userId) {
  return new Promise(
    function (resolve, reject) {
      db.collection('schemaB').aggregate([{
        $match: {
          'isDeleted': false,
          'schemaA': ObjectID(schemaAId)
        }
      },
      {
        $lookup: {
          from: "schemaC",
          localField: "_id",
          foreignField: "schemaBId",
          as: "schemasC"
        },
      },
      {
        $project: {
          _id: true,
          schemaAId: true,
          // other neccessary fields with true (several lines - makes code ugly and messy)
          schemasC: {
            "$arrayElemAt": [{
              $filter: {
                input: "$schamasC",
                as: "schemaC",
                cond: {
                  $eq: ["$$schemaC.userId", ObjectID(userId)]
                }
              }
            }, 0]
          }
        }
      }
    ]).toArray(function (error, result) {
      if (error) {
        reject(error);
      } else {
        resolve(result);
      };
    });
  });
}

Как с этим справитьсялучший способ?

1 Ответ

0 голосов
/ 02 декабря 2018

То, что вы пытаетесь сделать, лучше сделать, используя синтаксис mongodb 3.6 $lookup, который фильтрует документ внутри $lookup трубопровод

db.collection('schemaB').aggregate([
  { "$match": { "isDeleted": false, "schemaA": ObjectID(schemaAId) }},
  { "$lookup": {
    "from": "schemaC",
    "let": { "schemaBId": "$_id" },
    "pipeline": [
      { "$match": {
        "$expr": { "$eq": ["$schemaBId", "$$schemaBId"] },
        "userId": ObjectID("5b5c747d8209982630bbffe5")
      }}
    ],
    "as": "schemasC"
  }}
])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...