MongoDB-paging
Czy podczas korzystania z MongoDB, są jakieś specjalne wzorce do tworzenia np. widoku paged? powiedzmy blog, który zawiera listę najnowszych postów 10, gdzie możesz nawigować wstecz do starszych postów.
Lub Rozwiąż to za pomocą indeksu na np. blogpost.publishdate i po prostu pominąć i ograniczyć wynik?
6 answers
Używanie skip + limit nie jest dobrym sposobem na stronicowanie, gdy wydajność jest problemem lub przy dużych kolekcjach; będzie coraz wolniej, gdy zwiększysz liczbę stron. Użycie skip wymaga, aby serwer przechodził przez wszystkie dokumenty (lub wartości indeksu) od 0 do wartości offsetu (skip).
Znacznie lepiej jest użyć zapytania range (+limit), w którym przekazujesz wartość zakresu ostatniej strony. Na przykład, jeśli sortujesz według "publishdate", po prostu przekaż ostatnią wartość" publishdate" jako kryteria dla zapytania, aby uzyskać następną stronę danych.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-19 19:05:53
- stronicowanie oparte na zakresach jest trudne do zaimplementowania, jeśli trzeba sortować elementy na wiele sposobów.
- pamiętaj, jeśli wartość pola parametru sort nie jest unikalna , to stronicowanie oparte na zakresach stanie się nie do zrealizowania.
Możliwe rozwiązanie: spróbuj uprościć desgin, zastanawiając się, czy możemy sortować tylko według id lub jakiejś unikalnej wartości?
I jeśli możemy, możemy użyć pageingu opartego na zakresie.
Powszechnym sposobem jest użycie sort() , skip() i limit() do implementacji stronicowania co jest opisane powyżej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-15 04:48:42
To rozwiązanie, którego użyłem, gdy moja kolekcja stała się zbyt duża, aby powrócić w jednym zapytaniu. Wykorzystuje on nieodłączną kolejność pola _id
i pozwala na zapętlenie kolekcji według określonego rozmiaru partii.
Tutaj jest to moduł npm, mongoose-paging , Pełny kod znajduje się poniżej:
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;
};
Załącz go do swojego modelu w ten sposób:
MySchema.plugin(findPaged);
Następnie zapytanie tak:
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)
}
);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-13 19:55:10
Stronicowanie oparte na zakresie jest wykonalne, ale musisz być mądry, jak min / max zapytanie.
Jeśli możesz sobie na to pozwolić, spróbuj buforować wyniki zapytania w pliku tymczasowym lub kolekcji. Dzięki kolekcjom TTL w MongoDB możesz wstawić swoje wyniki do dwóch kolekcji.
- Search+User+Parameters Query (TTL whatever)
- wyniki zapytania (TTL whatever + cleaning interval + 1)
Korzystanie z obu zapewnia, że nie otrzymasz częściowych wyników, gdy TTL jest blisko aktualnego czasu. Możesz użyć prostego licznika podczas przechowywania wyników, aby wykonać bardzo proste zapytanie zakresu w tym momencie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-03 00:28:36
Oto przykład pobierania listy dokumentów User
w kolejności według CreatedDate
(Gdzie pageIndex
jest oparte na 0) przy użyciu oficjalnego sterownika C#.
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();
}
Wszystkie operacje sortowania i przywoływania są wykonywane po stronie serwera. Chociaż jest to przykład w C#, myślę, że to samo można zastosować do innych portów językowych.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-15 05:49:53
// 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-14 12:53:41