Запрос для расчета и возврата среднего рейтинга из другой коллекции?

#database #mongodb

Вопрос:

У меня есть две коллекции, компьютеры, которые показаны ниже

 {"_id":{"$oid":"6185bee4aca3214e77e748a9"},"name":"Gaming PC","manufacturer":"Dell","category":["Gaming"],"colour":"black","price":1200.0,"quantity":47.0,"weight":10.0,"parts":[{"type":"motherboard","manufacturer":"AMD","cost":150.0,"description":"Motherboard suitable for gaming PCs"},{"type":"ram","manufacturer":"Corsair","cost":50.0,"description":"16gb 2400mhz RAM"},{"type":"cpu","manufacturer":"Intel","cost":250.0,"description":"AMD 5600X Processor"},{"type":"gpu","manufacturer":"NVIDIA","cost":600.0,"description":"NVIDIA GTX3080"},{"type":"storage","manufacturer":"Seagate","cost":80.0,"description":"1TB SSD"}],"reviews":["review01","review02","review10"]},

{"_id":{"$oid":"6185c06eaca3214e77e748aa"},"name":"Office PC","manufacturer":"HP","category":["Work","Office"],"colour":"black","price":400.0,"quantity":102.0,"weight":12.0,"parts":[{"type":"motherboard","manufacturer":"XYZ","cost":70.0,"description":"Reliable motherboard"},{"type":"ram","manufacturer":"HP","cost":10.0,"description":"4gb 2400mhz RAM"},{"type":"cpu","manufacturer":"Intel","cost":100.0,"description":"Built In Processor"},{"type":"gpu","manufacturer":"HP","cost":75.0,"description":"On board graphics"},{"type":"storage","manufacturer":"Seagate","cost":20.0,"description":"1TB HDD"}],"reviews":["review03"]},

{"_id":{"$oid":"6185c244aca3214e77e748ab"},"name":"Chromebook","manufacturer":"Acer","category":["Portable","Lightweight","Work","Student"],"colour":"red","price":350.0,"quantity":61.0,"weight":4.0,"parts":[{"type":"motherboard","manufacturer":"XYZ","cost":40.0,"description":"Reliable motherboard for Laptops"},{"type":"ram","manufacturer":"Acer","cost":10.0,"description":"Built in 4gb RAM"},{"type":"cpu","manufacturer":"AMD","cost":100.0,"description":"Built In Processor"},{"type":"gpu","manufacturer":"Acer","cost":45.0,"description":"On board graphics"},{"type":"storage","manufacturer":"Acer","cost":25.0,"description":"64GB HDD"}],"reviews":["review04","review05"]}
 

И коллекция отзывов;

 {"_id":"review01","reviewer":"Jack Weir","rating":5.0,"text":"Very good product!","created":"2021, 08, 03"},
{"_id":"review02","reviewer":"Adam Smith","rating":3.0,"text":"Good value for money","created":"2021, 09, 04"},
{"_id":"review03","reviewer":"Luke Bridges","rating":1.0,"text":"Not good!","created":"2021, 10, 21"},
{"_id":"review04","reviewer":"Richard Lamb","rating":4.0,"text":"Runs very smoothly","created":"2021, 11, 03"},
{"_id":"review05","reviewer":"Pamela Halpert","rating":4.0,"text":"Easy to setup","created":"2021, 11, 04"},
{"_id":"review06","reviewer":"Michael Scott","rating":5.0,"text":"Would highly recommend","created":"2021, 11, 05"},
{"_id":"review07","reviewer":"Angela Lewis","rating":2.0,"text":"A bit too pricey","created":"2021, 11, 06"},
{"_id":"review08","reviewer":"Dexter Morgan","rating":3.0,"text":"Does the job","created":"2021, 11, 06"},
{"_id":"review09","reviewer":"Lisa Simpson","rating":2.0,"text":"Okay but not great","created":"2021, 11, 06"},
{"_id":"review10","reviewer":"Marge Simpson","rating":5.0,"text":"Wonderful Computer exactly what I was after!","created":"2021, 11, 07"}
 

Как мне написать запрос, который может возвращать название каждого продукта и среднюю оценку, которую он получил от любых оценок в свойстве «Обзор»?

Например, я хотел бы, чтобы результат запроса отображал «имя:» Игровой ПК», Средний рейтинг: 4,3″

Ответ №1:

Вам нужно только $lookup присоединиться к коллекциям (получить данные рецензентов в коллекцию компьютеров) и сделать $avg это, чтобы получить среднее значение.

 db.computers.aggregate({
  "$lookup": {
    "from": "reviews",
    "localField": "reviews",
    "foreignField": "_id",
    "as": "reviewers"
  }
},
{
  "$project": {
    "name": 1,
    "avg": {
      "$avg": "$reviewers.rating"
    }
  }
})
 

Пример здесь

Этот запрос выводит только данные name и avg поля, но вы можете добавить в $project этап столько полей, сколько захотите. Также вы можете использовать $set или $addFields вместо проекта, чтобы не потерять все значения (пример)