MongoDB Как правильно выполнить поиск документов в формате $lookup 2?

#mongodb #mongodb-query

#mongodb #mongodb-запрос

Вопрос:

Извините, я новичок, я использую поиск с двумя документами, здесь у меня есть 3 таблицы:

 const Product = {
 id: ObjectId,
 name: String
}

const user = {
 id: ObjectId,
 name: String
}

const comment = {
 id: ObjectId,
 product: ObjectId('product'),
 user: ObjectId('user'),
 parentComment: ObjectId('comment')
 text: String
}

const rate = {
 id: ObjectId,
 product: ObjectId('product'),
 user: ObjectId('user')
 rate: Number
}
  

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

 commentModel.aggregate([
                    {
                        $match:{
                            product: mongoose.Types.ObjectId(req.query.productID),
                            parent: null
                        },
                    },
                    {
                        $lookup:
                        {
                            'from': 'users',
                            'localField': 'user',
                            'foreignField': 'id',
                            'as': 'user'
                        }
                    },
                    {
                        $lookup:
                        {
                            'from': 'rates',
                            'pipeline': [
                                { $match: {product: mongoose.Types.ObjectId(req.query.productID), user: 'user.id'}}
                            ],
                            'as': 'rateValue'
                        }
                    }
                ])
  

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

Ответ №1:

Есть несколько исправлений,

  • Вам нужно $unwind деконструировать пользовательский массив, потому что $lookup не позволит присоединиться к полю массива,
  • чтобы сопоставить поле родительской коллекции в lookup, вы должны определить переменную с помощью let в lookup,
  • чтобы соответствовать выражению, вам нужно использовать $expr
 commentModel.aggregate([
  {
    $match: {
      product: mongoose.Types.ObjectId(req.query.productID),
      parentComment: null
    }
  },
  {
    $lookup: {
      from: "users",
      as: "user",
      localField: "user",
      foreignField: "id"
    }
  },
  // add this
  { $unwind: "$user" },
  {
    $lookup: {
      from: "rates",
      let: { userId: "$user.id" }, // add this
      pipeline: [
        {
          $match: {
            product: mongoose.Types.ObjectId(req.query.productID),
            $expr: { $eq: ["$user", "$$userId"] }
          }
        }
      ],
      as: "rateValue"
    }
  }
])
  

Игровая площадка


Другой вариант, без $unwind

Игровая площадка

Комментарии:

1. Большое вам спасибо за первый, он работает, но второй, можете ли вы объяснить, let: { userId: "$user" }, , $user ссылка на какой из них? Пользовательская модель или rateModel? Спасибо

2. идентификатор пользователя $ из модели комментариев, потому что, взглянув на свой запрос, вы заменяете пользователя при поиске на user as: 'user' но я использовал users , и поле user уже есть.

Ответ №2:

Вы также можете попробовать это

 [
    {
        $match:{
            product: mongoose.Types.ObjectId(req.query.productID),
            parent: null
        },
    },
    {
        $lookup: {
            'from': 'users',
            'localField': 'user',
            'foreignField': 'id',
            'as': 'user'
        }
    },
    {
        $lookup: {
            'from': 'rates',
            'localField': 'user',
            'foreignField': 'user',
            'as': 'rateDetail'
        }
    },
    {
        $unwind: '$rateDetail'
    },
    {
        $match: {
            '$rateDetail.product':mongoose.Types.ObjectId(req.query.productID)
        }
    }
]
  

Комментарии:

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