#node.js #database #mongodb #mongoose #nosql
#node.js #База данных #mongodb #mongoose #nosql
Вопрос:
У меня есть этот запрос mongo, чтобы получить список сообщений в потоке.
await db
.collection("threads")
.find({
_id: ObjectId(req.query.thread_id),
})
.project({
messages: {
$slice: [parseInt(req.query.offset), parseInt(req.query.limit)],
},
_id: 1,
date_created: 1,
})
.toArray();
Ограничение и смещение устанавливаются клиентом для поддержки неограниченной загрузки. Проблема в том, что запрос получает результат в том порядке, в котором они были добавлены, тогда как сначала он должен разбиваться на страницы с последними добавленными сообщениями. Как мне это сделать? Возможно ли, что я могу отменить массив перед выборкой или это слишком большая нагрузка?
Это моя схема потоков:
{
"_id":{
"$oid":"5f7b32c014014100176c2a55"
},
"thread_name":"personal",
"messages":[
{
"_id":{
"$oid":"5f7b32d414014100176c2a56"
},
"sender":{
"$oid":"5f7b329114014100176c2a52"
},
"type":"text",
"date_created":{
"$date":"2020-10-05T14:51:00.716Z"
},
"content":"hi"
},
{
"_id":{
"$oid":"5f7b32df14014100176c2a57"
},
"sender":{
"$oid":"5f7b329114014100176c2a52"
},
"type":"text",
"date_created":{
"$date":"2020-10-05T14:51:11.302Z"
},
"content":"hello"
},
],
"date_created":{
"$date":"2020-10-05T14:50:40.271Z"
},
}
Ответ №1:
Вы можете использовать $reverseArray
опцию при агрегировании
Сначала aggregate
вы можете использовать $match
(оно заменит вашу find
часть), а затем с $project
помощью вы можете добавить новое свойство, например reversedMessages
, где вы будете использовать $ reverseArray и $ slice вместе взятые
итак, запрос должен быть примерно таким
db.collection("threads").aggregate([
{
$match: {
_id: ObjectId(req.query.thread_id),
},
},
{
$project: {
_id: 1,
date_created: 1,
reverseMessages: {
$slice: [
{ $reverseArray: "$messages" },
0,
parseInt(req.query.limit), // I guess you want to return latest n messages, where n is a limit from query
],
},
},
},
]);
Комментарии:
1. Это не всегда последние n сообщений, в некоторых случаях пользователь прокручивает до конца, и извлекаются следующие n сообщений.
2. ну, тогда вы можете вместо
0
того, чтобы использовать в качестве начала фрагмента количество сообщений, которые он уже загрузил (я думаю, это такoffset
), а затем в качестве 2-го параметра, который вы делаетеoffset limit
, где, я думаю, limit — это количество сообщений, которые вы хотите получить3. По какой-то причине, когда я запускаю запрос, я получаю следующее:
MongoError: $slice array wrong size
чего не было в предыдущем запросе. Есть идеи, почему?4. возможно, предоставленные вами числа выходят за рамки массива? потому что, если длина массива равна 10, и вы предоставляете
$slice: [array, 1, 15]
, может быть, это выдаст вам ошибку? не совсем уверен, что я протестировал его на какой-то коллекции, которая у меня есть, и она работала нормально5. В основном я начинаю с 0. Длина массива составляет 25 , и я установил ограничение только на 5.
Ответ №2:
«Возможно ли, что я могу инвертировать массив перед выборкой?» Вы не можете отменить то, чего у вас нет. Я видел другой ответ, $reverseArray
но зачем тратить ресурсы на изменение массива, когда вы можете просто $ slice последние элементы?
Если значение отрицательное, $slice возвращает до последних n элементов в массиве. n не может быть преобразовано в отрицательное число, если указано
db.collection("threads").aggregate([
{
$match: {
_id: ObjectId(req.query.thread_id),
},
},
{
$project: {
_id: 1,
date_created: 1,
reverseMessages: {
$slice: [
"$messages",
parseInt(req.query.limit) * -1
]
}
}
}
]);
Комментарии:
1. Я не всегда хочу получать последние n сообщений, иногда я хочу получить вторую страницу из последней, в этот момент как это работает?