Подтвердить что ты не робот

MongoDB - пейджинг

При использовании MongoDB существуют ли какие-либо специальные шаблоны для создания, например. просматриваемый просмотр? скажем, в блоге, в котором перечислены 10 последних сообщений, в которых вы можете перемещаться назад к более старым сообщениям.

Или разрешить его с помощью индекса напр. blogpost.publishdate и просто пропустить и ограничить результат?

4b9b3361

Ответ 1

Использование ограничения skip + не является хорошим способом сделать подкачку, когда производительность является проблемой или с большими коллекциями; при увеличении номера страницы он будет медленнее и медленнее. Использование skip требует, чтобы сервер шел по всем документам (или значениям индекса) от 0 до значения смещения (skip).

Гораздо лучше использовать запрос диапазона (+ предел), в котором вы передаете значение диапазона последней страницы. Например, если вы сортируете по "publishdate", вы просто передадите последнее значение "publishdate" в качестве критериев запроса для получения следующей страницы данных.

Ответ 2

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

Возможное решение: попробуйте упростить desgin, думая о том, можем ли мы сортировать только по id или какое-то уникальное значение?

И если мы можем, то можно использовать отображение на основе диапазона.

Общим способом является использование sort(), skip() и limit() для реализации подкачки, что описано выше.

Ответ 3

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

Здесь он является модулем npm, mongoose-paging, полный код ниже:

function promiseWhile(condition, action) {
  return new Promise(function(resolve, reject) {
    process.nextTick(function loop() {
      if(!condition()) {
        resolve();
      } else {
        action().then(loop).catch(reject);
      }
    });
  });
}

function findPaged(query, fields, options, iterator, cb) {
  var Model  = this,
    step     = options.step,
    cursor   = null,
    length   = null;

  promiseWhile(function() {
    return ( length===null || length > 0 );
  }, function() {
    return new Promise(function(resolve, reject) {

        if(cursor) query['_id'] = { $gt: cursor };

        Model.find(query, fields, options).sort({_id: 1}).limit(step).exec(function(err, items) {
          if(err) {
            reject(err);
          } else {
            length  = items.length;
            if(length > 0) {
              cursor  = items[length - 1]._id;
              iterator(items, function(err) {
                if(err) {
                  reject(err);
                } else {
                  resolve();
                }
              });
            } else {
              resolve();
            }
          }
        });
      });
  }).then(cb).catch(cb);

}

module.exports = function(schema) {
  schema.statics.findPaged = findPaged;
};

Прикрепите его к вашей модели следующим образом:

MySchema.plugin(findPaged);

Затем выполните следующие запросы:

MyModel.findPaged(
  // mongoose query object, leave blank for all
  {source: 'email'},
  // fields to return, leave blank for all
  ['subject', 'message'],
  // number of results per page
  {step: 100},
  // iterator to call on each set of results
  function(results, cb) {
    console.log(results);
    // this is called repeatedly while until there are no more results.
    // results is an array of maximum length 100 containing the
    // results of your query

    // if all goes well
    cb();

    // if your async stuff has an error
    cb(err);
  },
  // function to call when finished looping
  function(err) {
    throw err;
    // this is called once there are no more results (err is null),
    // or if there is an error (then err is set)
  }
);

Ответ 4

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

Если вы можете себе позволить, попробуйте кэшировать результаты запроса во временном файле или коллекции. Благодаря коллекциям TTL в MongoDB вы можете вставить свои результаты в две коллекции.

  • Поиск + Пользователь + запрос параметров (TTL независимо)
  • Результаты запроса (TTL независимо + интервал очистки + 1)

Используя оба подтверждения, вы не получите частичных результатов, когда TTL близок к текущему времени. Вы можете использовать простой счетчик, когда вы сохраняете результаты, чтобы сделать запрос ОЧЕНЬ простой диапазон в этой точке.

Ответ 5

Ниже приведен пример получения списка заказов User документов CreatedDate (где pageIndex на основе нуля) с использованием официального драйвера С#.

public void List<User> GetUsers() 
{
  var connectionString = "<a connection string>";
  var client = new MongoClient(connectionString);
  var server = client.GetServer();
  var database = server.GetDatabase("<a database name>");

  var sortBy = SortBy<User>.Descending(u => u.CreatedDate);
  var collection = database.GetCollection<User>("Users");
  var cursor = collection.FindAll();
  cursor.SetSortOrder(sortBy);

  cursor.Skip = pageIndex * pageSize;
  cursor.Limit = pageSize;
  return cursor.ToList();
}

Все операции сортировки и подкачки выполняются на стороне сервера. Хотя это пример в С#, я думаю, что то же самое можно применить и к другим языковым портам.

См. http://docs.mongodb.org/ecosystem/tutorial/use-csharp-driver/#modifying-a-cursor-before-enumerating-it.

Ответ 6

    // file:ad-hoc.js
    // an example of using the less binary as pager in the bash shell
    //
    // call on the shell by:
    // mongo localhost:27017/mydb ad-hoc.js | less
    //
    // note ad-hoc.js must be in your current directory
    // replace the 27017 wit the port of your mongodb instance
    // replace the mydb with the name of the db you want to query
    //
    // create the connection obj
    conn = new Mongo();

    // set the db of the connection
    // replace the mydb with the name of the db you want to query
    db = conn.getDB("mydb");

    // replace the products with the name of the collection
    // populate my the products collection
    // this is just for demo purposes - you will probably have your data already
    for (var i=0;i<1000;i++ ) {
    db.products.insert(
        [
            { _id: i, item: "lamp", qty: 50, type: "desk" },
        ],
        { ordered: true }
    )
    }


    // replace the products with the name of the collection
    cursor = db.products.find();

    // print the collection contents
    while ( cursor.hasNext() ) {
        printjson( cursor.next() );
    }
    // eof file: ad-hoc.js