Tengo una colección T
, con 2 campos: Grade1
y Grade2
, y quiero seleccionar aquellos con condición Grade1 > Grade2
, ¿cómo puedo obtener una consulta como en MySQL?
Select * from T Where Grade1 > Grade2
Tengo una colección T
, con 2 campos: Grade1
y Grade2
, y quiero seleccionar aquellos con condición Grade1 > Grade2
, ¿cómo puedo obtener una consulta como en MySQL?
Select * from T Where Grade1 > Grade2
Respuestas:
Puede usar $ where. Solo tenga en cuenta que será bastante lento (tiene que ejecutar código Javascript en cada registro), así que combine con consultas indexadas si puede.
db.T.find( { $where: function() { return this.Grade1 > this.Grade2 } } );
o más compacto:
db.T.find( { $where : "this.Grade1 > this.Grade2" } );
puede usar $expr
como se describe en la respuesta reciente
$where: function() { return this.Grade1 - this.Grade2 > variable }
?
db.T.find({$where: function() {return this.startDate == ISODate("2017-01-20T10:55:08.000Z");}});
no devuelve nada, incluso uno de los documentos de la colección es ISODate("2017-01-20T10:55:08.000Z")
. Pero <=
y >=
parece trabajo. ¿alguna idea?
this.startDate.getTime() == ISODate("2017-01-20T10:55:08.000Z").getTime()
Puede usar $ expr (operador de versión 3.6 de mongo) para usar funciones de agregación en una consulta normal.
Comparar query operators
vs aggregation comparison operators
.
Consulta regular:
db.T.find({$expr:{$gt:["$Grade1", "$Grade2"]}})
Consulta de agregación:
db.T.aggregate({$match:{$expr:{$gt:["$Grade1", "$Grade2"]}}})
Si su consulta consta solo del $where
operador, puede pasar solo la expresión JavaScript:
db.T.find("this.Grade1 > this.Grade2");
Para un mayor rendimiento, ejecute una operación agregada que tenga un $redact
canalización para filtrar los documentos que satisfacen la condición dada.
La $redact
canalización incorpora la funcionalidad de $project
e $match
implementar la redacción a nivel de campo, donde devolverá todos los documentos que coincidan con la condición que usa $$KEEP
y elimina de los resultados de la canalización aquellos que no coincidan con la $$PRUNE
variable.
Al ejecutar la siguiente operación agregada, se filtran los documentos de manera más eficiente que con $where
colecciones grandes, ya que se usa una única canalización y operadores nativos de MongoDB, en lugar de evaluaciones de JavaScript con $where
, lo que puede ralentizar la consulta:
db.T.aggregate([
{
"$redact": {
"$cond": [
{ "$gt": [ "$Grade1", "$Grade2" ] },
"$$KEEP",
"$$PRUNE"
]
}
}
])
que es una versión más simplificada de incorporar las dos canalizaciones $project
y $match
:
db.T.aggregate([
{
"$project": {
"isGrade1Greater": { "$cmp": [ "$Grade1", "$Grade2" ] },
"Grade1": 1,
"Grade2": 1,
"OtherFields": 1,
...
}
},
{ "$match": { "isGrade1Greater": 1 } }
])
Con MongoDB 3.4 y versiones posteriores:
db.T.aggregate([
{
"$addFields": {
"isGrade1Greater": { "$cmp": [ "$Grade1", "$Grade2" ] }
}
},
{ "$match": { "isGrade1Greater": 1 } }
])
En caso de que el rendimiento sea más importante que la legibilidad y siempre que su condición consista en operaciones aritméticas simples, puede usar la canalización de agregación. Primero, use $ project para calcular el lado izquierdo de la condición (lleve todos los campos al lado izquierdo). Luego use $ match para comparar con una constante y un filtro. De esta forma evita la ejecución de JavaScript. A continuación se muestra mi prueba en Python:
import pymongo
from random import randrange
docs = [{'Grade1': randrange(10), 'Grade2': randrange(10)} for __ in range(100000)]
coll = pymongo.MongoClient().test_db.grades
coll.insert_many(docs)
Usando agregado:
%timeit -n1 -r1 list(coll.aggregate([
{
'$project': {
'diff': {'$subtract': ['$Grade1', '$Grade2']},
'Grade1': 1,
'Grade2': 1
}
},
{
'$match': {'diff': {'$gt': 0}}
}
]))
1 bucle, lo mejor de 1: 192 ms por bucle
Usando buscar y $ donde:
%timeit -n1 -r1 list(coll.find({'$where': 'this.Grade1 > this.Grade2'}))
1 bucle, lo mejor de 1: 4,54 s por bucle