Mongo DB реверсирует поле массива перед нарезкой

#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 сообщений, иногда я хочу получить вторую страницу из последней, в этот момент как это работает?