tutorial - mongodb ventajas y desventajas
Obtenga un recuento del total de documentos con MongoDB al usar el límite (9)
Es posible obtener el tamaño total del resultado sin el efecto de limit()
utilizando count()
como se responde aquí: ¿ Limita los resultados en MongoDB pero sigue obteniendo el conteo completo?
De acuerdo con la documentación, incluso puede controlar si se tiene en cuenta el límite / paginación al llamar a count()
: https://docs.mongodb.com/manual/reference/method/cursor.count/#cursor.count
Edición: en contraste con lo que está escrito en otra parte, los documentos indican claramente que "La operación no realiza la consulta, sino que cuenta los resultados que devolvería la consulta" . Lo cual, a mi entender, significa que solo se ejecuta una consulta.
Ejemplo:
> db.createCollection("test")
{ "ok" : 1 }
> db.test.insert([{name: "first"}, {name: "second"}, {name: "third"},
{name: "forth"}, {name: "fifth"}])
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 5,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})
> db.test.find()
{ "_id" : ObjectId("58ff00918f5e60ff211521c5"), "name" : "first" }
{ "_id" : ObjectId("58ff00918f5e60ff211521c6"), "name" : "second" }
{ "_id" : ObjectId("58ff00918f5e60ff211521c7"), "name" : "third" }
{ "_id" : ObjectId("58ff00918f5e60ff211521c8"), "name" : "forth" }
{ "_id" : ObjectId("58ff00918f5e60ff211521c9"), "name" : "fifth" }
> db.test.count()
5
> var result = db.test.find().limit(3)
> result
{ "_id" : ObjectId("58ff00918f5e60ff211521c5"), "name" : "first" }
{ "_id" : ObjectId("58ff00918f5e60ff211521c6"), "name" : "second" }
{ "_id" : ObjectId("58ff00918f5e60ff211521c7"), "name" : "third" }
> result.count()
5 (total result size of the query without limit)
> result.count(1)
3 (result size with limit(3) taken into account)
Estoy interesado en optimizar una solución de "paginación" en la que estoy trabajando con MongoDB. Mi problema es sencillo. Generalmente limito el número de documentos devueltos usando la funcionalidad limit()
. Esto me obliga a emitir una consulta redundante sin la función de limit()
para que también pueda capturar el número total de documentos en la consulta, de modo que pueda pasar al cliente para informarles que tendrán que emitir una solicitud adicional. (s) para recuperar el resto de los documentos.
¿Hay una manera de condensar esto en 1 consulta? Obtenga el número total de documentos, pero al mismo tiempo, solo recupere un subconjunto utilizando limit()
. ¿Hay una manera diferente de pensar sobre este problema que la que estoy abordando?
Hay una manera en Mongodb 3.4: $ faceta
tu puedes hacer
db.collection.aggregate([
{
$facet: {
data: [{ $match: {} }],
total: { $count: ''total'' }
}
}
])
entonces podrás ejecutar dos agregados al mismo tiempo
Intenta lo siguiente:
cursor.count (false, function (err, total) {console.log ("total", total)})
core.db.users.find(query, {}, {skip:0, limit:1}, function(err, cursor){
if(err)
return callback(err);
cursor.toArray(function(err, items){
if(err)
return callback(err);
cursor.count(false, function(err, total){
if(err)
return callback(err);
console.log("cursor", total)
callback(null, {items: items, total:total})
})
})
})
Los tiempos han cambiado, y creo que puede lograr lo que pide el OP al usar la agregación con $sort
, $group
y $project
. Para mi sistema, también necesitaba obtener información del usuario de mi colección de users
. Esperemos que esto pueda responder cualquier pregunta sobre eso también. A continuación se muestra un tubo de agregación. Los últimos tres objetos (ordenación, grupo y proyecto) son los que manejan la obtención del recuento total y luego brindan capacidades de paginación.
db.posts.aggregate([
{ $match: { public: true },
{ $lookup: {
from: ''users'',
localField: ''userId'',
foreignField: ''userId'',
as: ''userInfo''
} },
{ $project: {
postId: 1,
title: 1,
description: 1
updated: 1,
userInfo: {
$let: {
vars: {
firstUser: {
$arrayElemAt: [''$userInfo'', 0]
}
},
in: {
username: ''$$firstUser.username''
}
}
}
} },
{ $sort: { updated: -1 } },
{ $group: {
_id: null,
postCount: { $sum: 1 },
posts: {
$push: ''$$ROOT''
}
} },
{ $project: {
_id: 0,
postCount: 1,
posts: {
$slice: [
''$posts'',
currentPage ? (currentPage - 1) * RESULTS_PER_PAGE : 0,
RESULTS_PER_PAGE
]
}
} }
])
MongoDB le permite usar cursor.count()
incluso cuando pasa limit()
o skip()
.
Digamos que tienes un db.collection
con 10 artículos.
Tu puedes hacer:
async function getQuery() {
let query = await db.collection.find({}).skip(5).limit(5); // returns last 5 items in db
let countTotal = await query.count() // returns 10-- will not take `skip` or `limit` into consideration
let countWithConstraints = await query.count(true) // returns 5 -- will take into consideration `skip` and `limit`
return { query, countTotal }
}
Mongodb 3.4 ha introducido agregación de $facet
que procesa múltiples tuberías de agregación dentro de una sola etapa en el mismo conjunto de documentos de entrada.
Con $facet
y $group
puede encontrar documentos con $limit
y puede obtener el recuento total.
Puedes usar la siguiente agregación en mongodb 3.4
db.collection.aggregate([
{ "$facet": {
"totalData": [
{ "$match": { }},
{ "$skip": 10 },
{ "$limit": 10 }
],
"totalCount": [
{ "$group": {
"_id": null,
"count": { "$sum": 1 }
}}
]
}}
])
Incluso puede usar la agregación de $count
que se ha introducido en mongodb 3.6 .
Puedes usar la siguiente agregación en mongodb 3.6
db.collection.aggregate([
{ "$facet": {
"totalData": [
{ "$match": { }},
{ "$skip": 10 },
{ "$limit": 10 }
],
"totalCount": [
{ "$count": "count" }
]
}}
])
Puede hacer esto en una consulta. Primero ejecuta un conteo y dentro de eso ejecuta la función limit ().
En Node.js y Express.js, tendrá que usarlo así para poder usar la función "contar" junto con el "resultado" de toArray.
var curFind = db.collection(''tasks'').find({query});
Luego puedes ejecutar dos funciones como esta (una anidada en la otra)
curFind.count(function (e, count) {
// Use count here
curFind.skip(0).limit(10).toArray(function(err, result) {
// Use result here and count here
});
});
Todo depende de la experiencia de paginación que necesite para saber si necesita hacer dos consultas.
¿Necesita enumerar cada página o incluso un rango de páginas? ¿Alguien incluso va a la página 1051 - conceptualmente, qué significa eso realmente?
Ha habido muchos UX en los patrones de paginación: evitar los dolores de paginación que cubren varios tipos de paginación y sus escenarios y muchos no necesitan una consulta de conteo para saber si hay una página siguiente. Por ejemplo, si muestra 10 elementos en una página y limita a 13, sabrá si hay otra página.
No , no hay otra manera. Dos consultas - una para el conteo - una con límite. O tienes que usar una base de datos diferente. Apache Solr, por ejemplo, funciona como usted quiere. Cada consulta allí es limitada y devuelve totalCount.