Я хотел бы начать с того, что , если ваш проект использует реляционные данные, я настоятельно рекомендую вам использовать реляционную базу данных вместо MongoDb . Я люблю Mongodb так же, как и следующего парня, и делал проекты в Mongodb, используя реляционные данные, но я столкнулся с проблемами, и я видел и слышал о слишком многих проектах, которые начинались с Mongodb, которые должны были go через болезненная миграция, когда проект стал слишком большим.
Однако, если вы настаиваете на использовании Mongodb, я бы сделал следующее:
Отказ от ответственности : я никогда не использовал Понедельник goose, поэтому я просто собираюсь придерживаться схемы Mongodb и запросов.
Для целей этого ответа я высмеял некоторые JSON данные из Mockeroo (https://mockaroo.com/).
Давайте сначала придумаем некоторые базовые c детали для вашей схемы коллекции ресторана (модель).
{
"_id": "Bujxd5U6k924D0M04NF2kOT6",
"address": "Curabitur gravida nisi at nibh. In hac habitasse platea dictumst. Aliquam augue quam, sollicitudin vitae, consectetuer eget, rutrum at, lorem.",
"name": "Stringtough"
},
{
"_id": "EA50k3O5vxEi543z949L6u8M",
"address": "Etiam vel augue. Vestibulum rutrum rutrum neque. Aenean auctor gravida sem.",
"name": "Zontrax"
},
{
"_id": "LOs7NI67ijwH1g26e38067G0",
"address": "Proin eu mi. Nulla ac enim. In tempor, turpis nec euismod scelerisque, quam turpis adipiscing lorem, vitae mattis nibh ligula nec sem.",
"name": "Holdlamis"
}
Это только основные c детали, которые нам понадобятся для запроса среднего рейтинга; у вас, вероятно, гораздо больше деталей в вашей коллекции ресторанов.
Мы можем сгенерировать аналогичные данные для пользователей , где у каждого пользователя будет _id, name, email et c, но это не так слишком важен для целей этого ответа.
Теперь давайте перейдем к коллекции отзывов .
Когда пользователь просматривает ресторан, ему обычно требуется короткий параграф обзора и цифра c рейтинг. Я бы не высказался бы за вложение всех рецензий в массив, и, как вы упомянули в вопросе, создал бы другую коллекцию для хранения всех рецензий. Таким образом, наша коллекция "обзоров" будет выглядеть примерно так:
{
"_id": "0M63HJQ9MKXR538084U92Zt2",
"restaurant_id": "EA50k3O5vxEi543z949L6u8M",
"user_id": "s0j45hXpv4tgCAl5vD8a2b87",
"rating": 4.8,
"review": "Maecenas tristique, est et tempus semper, est quam pharetra magna, ac consequat metus sapien ut nunc. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Mauris viverra diam vitae quam. Suspendisse potenti.\n\nNullam porttitor lacus at turpis. Donec posuere metus vitae ipsum. Aliquam non mauris.",
"date": "2019-06-03T06:36:19.000Z"
},
{
"_id": "9K13616ouSn5H2o17l5Xp0x6",
"restaurant_id": "LOs7NI67ijwH1g26e38067G0",
"user_id": "RvYx1J1mU532iD3833286I7h",
"rating": 2.3,
"review": "Nulla ut erat id mauris vulputate elementum. Nullam varius. Nulla facilisi.",
"date": "2019-09-10T06:31:43.000Z"
},
{
"_id": "754233Q64d553XguY2Vi28a2",
"restaurant_id": "EA50k3O5vxEi543z949L6u8M",
"user_id": "s0j45hXpv4tgCAl5vD8a2b87",
"rating": 4.7,
"review": "Nulla ut erat id mauris vulputate elementum. Nullam varius. Nulla facilisi.\n\nCras non velit nec nisi vulputate nonummy. Maecenas tincidunt lacus at velit. Vivamus vel nulla eget eros elementum pellentesque.",
"date": "2019-06-04T02:17:01.000Z"
}, //and so on...
Обратите внимание, что между коллекциями "пользователи", "рестораны" и "отзывы" пары пользователей-отзывов и ресторанов-отзывов будут иметь одно отношения ко многим. Поэтому каждый документ в коллекции обзоров должен иметь restaurant_id и user_id (предпочтительно Mongodb ObjectIds), которые будут «внешними ключами» (своего рода) для других коллекций «restaurant» и «users». У каждого такого идентификатора будет только один, поскольку только один пользователь может написать конкретный отзыв, и что один отзыв не может быть написан для нескольких ресторанов. Затем, конечно, у нас есть поле «обзор», которое пишет пользователь, и «рейтинг», представляющий собой число с плавающей запятой, из 5.
Итак, скажем, у нас есть страница, где для каждого ресторана мы хотим отобразить название, количество отзывов и средний рейтинг. Как мы можем выполнить sh это?
Я написал следующий запрос агрегации для получения необходимых данных:
db.restaurants.aggregate([{
$lookup: {
from: "reviews",
"let": {
restaurant_id: "$_id"
},
pipeline: [{
$match: {
$expr: {
$eq: [
"$restaurant_id",
"$$restaurant_id"
]
}
}
},
{
$group: {
_id: null,
"number_of_ratings": {
$sum: 1
},
"average_rating": {
$avg: "$rating"
}
}
}
],
as: "review_stats"
}
},
{
$unwind: {
path: "$review_stats"
}
},
{
$unset: "review_stats._id"
}])
Результат должен выглядеть примерно так:
[{
"_id": "Bujxd5U6k924D0M04NF2kOT6",
"address": "Curabitur gravida nisi at nibh. In hac habitasse platea dictumst. Aliquam augue quam, sollicitudin vitae, consectetuer eget, rutrum at, lorem.",
"name": "Stringtough",
"review_stats":
{
"average_rating": 3.1285714285714286,
"number_of_ratings": 7
}
},
{
"_id": "EA50k3O5vxEi543z949L6u8M",
"address": "Etiam vel augue. Vestibulum rutrum rutrum neque. Aenean auctor gravida sem.",
"name": "Zontrax",
"review_stats":
{
"average_rating": 4,
"number_of_ratings": 4
}
},
{
"_id": "LOs7NI67ijwH1g26e38067G0",
"address": "Proin eu mi. Nulla ac enim. In tempor, turpis nec euismod scelerisque, quam turpis adipiscing lorem, vitae mattis nibh ligula nec sem.",
"name": "Holdlamis",
"review_stats":
{
"average_rating": 2.325,
"number_of_ratings": 4
}
}]
Я настоятельно рекомендую вам попробовать его на Пн go Детская площадка (после издевательств над 3 ресторанными документами и 15 отзывами): https://mongoplayground.net/p/Pyfqus2w-fl
Есть другие запросы, которые могут быть легко получены с помощью этой схемы, например, просмотр всех ресторанов, просмотренных пользователем, получение исторических или недавних обзоров ресторана (с указанием определенного диапазона дат) и т. Д. c. Но для цели этого ответа я думаю, что этого достаточно. Надеюсь, вам понравилось, пожалуйста, не стесняйтесь указывать улучшения.