пн goose рекурсивное вложение - PullRequest
       48

пн goose рекурсивное вложение

1 голос
/ 20 февраля 2020

В моем проекте пользователь может создавать продукты. у каждого пользователя есть ссылка на все его продукты, и у каждого продукта есть ссылка на его пользователя.

и у пользователя, и у продукта есть поле 'name'.

мне нужно получить все из массива продуктов пользователей, и в этом массиве я хочу иметь имя продукта и имя пользователя, который его создал (и только те поля и никакие другие).

например:

Users :

{ _id: 1, name: 'josh', productIds: [1,3]}
{ _id: 2, name: 'sheldon', productIds: [2]}

Продукты:

{ _id: 1, name: 'table', price: 45, userId: 1}
{ _id: 2, name: 'television', price: 25 userId: 2}
{ _id: 3, name: 'chair', price: 14 userId: 1}

Я хочу получить следующий результат:

{ _id: 1, name: 'josh', 
    products: {
        { _id: 1, name: 'table', user: { _id: 1, name: 'josh' },
        { _id: 3, name: 'chair', user: { _id: 1, name: 'josh' },
    }
}
{ _id: 2, name: 'sheldon', 
    products: {
        { _id: 2, name: 'television', userId: { _id: 2, name: 'sheldon' }
    }
}

Я пробовал следующий запрос, который не заполняет внутреннюю userId и оставил его только с идентификатором (без имени):

User.aggregate([
  { 
    $lookup: 
      { 
        from: 'products',
        localField: 'productIds',
        foreignField: '_id',
        as: 'products' 
      }  
  }

Я также попробовал следующее, которое проделало то же самое, что и первый запрос, за исключением того, что он только повторил первый продукт для каждого пользователя:

User.aggregate([
  { 
    $lookup: 
      { 
        from: 'products',
        localField: 'productIds',
        foreignField: '_id',
        as: 'products' 
      }  
  },
  {
    $unwind: {
      path: "$products",
      preserveNullAndEmptyArrays: true
    }
  },
  {
    $lookup: {
      from: "user",
      localField: "products.userId",
      foreignField: "_id",
      as: "prodUsr",
    }
  },
  {
    $group: {
      _id : "$_id",
      products: { $push: "$products" },
      "doc": { "$first": "$$ROOT" }
    }
  },
  {
    "$replaceRoot": {
    "newRoot": "$doc"
    }
}

Продукт:

const schema = new Schema(
  {
    name: {
      type: String,
      required: true
    },
    price: {
      type: Number,
      required: true
    },
    userId: {
      type: Schema.Types.ObjectId, 
      ref: 'User',
      required: true
    },
  }
);

module.exports = mongoose.model('Product', schema);

Пользователь:

const schema = new Schema(
  {
    name: {
      type: String,
      required: true,
      unique: true
    },
    productIds: [{
      type: Schema.Types.ObjectId, 
      ref: 'Product',
      require: false
    }],
  { timestamps: true }
);

module.exports = mongoose.model('User', schema);

любая помощь будет высоко ценится

1 Ответ

1 голос
/ 20 февраля 2020

Это выглядит как идеальный сценарий для поиска $ с пользовательским конвейером и другим вложенным $lookup. Внутренний позволяет обрабатывать отношения product-> user, а внешний обрабатывает user -> product one:

db.Users.aggregate([
    {
        $project: {
            productIds: 0
        }
    },
    {
        $lookup: {
            from: "Products",
            let: { user_id: "$_id" },
            pipeline: [
                {
                    $match: {
                        $expr: {
                            $eq: [ "$userId", "$$user_id" ]
                        }
                    }
                },
                {
                    $lookup: {
                        from: "Users",
                        localField: "userId",
                        foreignField: "_id",
                        as: "user"
                    }
                },
                {
                    $unwind: "$user"
                },
                {
                    $project: {
                        "user.productIds": 0,
                        "price": 0,
                        "userId": 0
                    }
                }
            ],
            as: "products"
        }
    }
])

Пн go Детская площадка

...