¿Cuál es la sintaxis para realizar una búsqueda de $ en un campo que es una matriz de ObjectIds en lugar de un solo ObjectId?
Ejemplo de documento de pedido:
{
_id: ObjectId("..."),
products: [
ObjectId("..<Car ObjectId>.."),
ObjectId("..<Bike ObjectId>..")
]
}
Consulta que no funciona:
db.orders.aggregate([
{
$lookup:
{
from: "products",
localField: "products",
foreignField: "_id",
as: "productObjects"
}
}
])
Resultado deseado
{
_id: ObjectId("..."),
products: [
ObjectId("..<Car ObjectId>.."),
ObjectId("..<Bike ObjectId>..")
],
productObjects: [
{<Car Object>},
{<Bike Object>}
],
}
mongodb
mongodb-query
aggregation-framework
Jason Lin
fuente
fuente
Respuestas:
Actualización de 2017
$ lookup ahora puede usar directamente una matriz como campo local .
$unwind
ya no es necesario.Respuesta antigua
La
$lookup
etapa de canalización agregación no funcionará directamente con una matriz. La intención principal del diseño es una "combinación izquierda" como un tipo de combinación "uno a muchos" (o realmente una "búsqueda") de los posibles datos relacionados. Pero el valor está destinado a ser singular y no una matriz.Por lo tanto, primero debe "desnormalizar" el contenido antes de realizar la
$lookup
operación para que esto funcione. Y eso significa usar$unwind
:Después de que
$lookup
coincida con cada miembro de la matriz, el resultado es una matriz en sí misma, por lo que$unwind
nuevamente y$group
a$push
nuevas matrices para el resultado final.Tenga en cuenta que cualquier coincidencia de "unión izquierda" que no se encuentre creará una matriz vacía para los "productObjects" en el producto dado y, por lo tanto, anulará el documento para el elemento "producto" cuando
$unwind
se llame al segundo .Aunque una aplicación directa a una matriz estaría bien, así es como funciona actualmente al hacer coincidir un valor singular con varios posibles.
Como
$lookup
es básicamente muy nuevo, actualmente funciona como sería familiar para aquellos que están familiarizados con la mangosta como una "versión de hombre pobre" del.populate()
método que se ofrece allí. La diferencia es que$lookup
ofrece el procesamiento del "lado del servidor" de la "unión" en contraposición al del cliente y que parte de la "madurez"$lookup
falta actualmente en las.populate()
ofertas (como interpolar la búsqueda directamente en una matriz).En realidad, este es un problema asignado para mejorar SERVER-22881 , por lo que, con algo de suerte, llegaría a la próxima versión o poco después.
Como principio de diseño, su estructura actual no es ni buena ni mala, sino que está sujeta a gastos generales al crear cualquier "unión". Como tal, se aplica el principio básico de MongoDB en el inicio, donde si "puede" vivir con los datos "pre-unidos" en una colección, entonces es mejor hacerlo.
La otra cosa que se puede decir
$lookup
como principio general es que la intención de la "unión" aquí es trabajar al revés de lo que se muestra aquí. Entonces, en lugar de mantener los "ID relacionados" de los otros documentos dentro del documento "principal", el principio general que funciona mejor es que los "documentos relacionados" contienen una referencia al "padre".Por tanto,
$lookup
se puede decir que "funciona mejor" con un "diseño de relación" que es lo contrario de cómo algo como la mangosta.populate()
realiza sus uniones del lado del cliente. Al identificar el "uno" dentro de cada "muchos" en su lugar, simplemente extrae los elementos relacionados sin necesidad de$unwind
la matriz primero.fuente
$lookup
y la validación de documentos como características en su infancia y que probablemente mejorarán. Por tanto, la expansión directa en una matriz sería bienvenida, al igual que una "consulta" para filtrar resultados. Ambos estarían mucho más alineados con el.populate()
proceso de la mangosta al que muchos están acostumbrados. Agregar el enlace del problema directamente en el contenido de la respuesta.$lookup
ahora funciona directamente en una matriz.A partir de MongoDB v3.4 (lanzado en 2016), la
$lookup
etapa de canalización de agregación también puede funcionar directamente con una matriz . No hay necesidad de$unwind
más.Esto se rastreó en SERVER-22881 .
fuente
También puede utilizar el
pipeline
escenario para realizar comprobaciones en una matriz de subdocumentos.Aquí está el ejemplo usando
python
(lo siento, soy gente serpiente).La trampa aquí es hacer coincidir todos los objetos en el
ObjectId
array
(extraño_id
que está en ellocal
campo / propproducts
).También puede limpiar o proyectar los registros externos con correos
stage
electrónicos adicionales , como se indica en el comentario anterior.fuente
usar $ relajarse obtendrá el primer objeto en lugar de una matriz de objetos
consulta:
resultado:
fuente
La agregación con
$lookup
y subsiguiente$group
es bastante engorrosa, por lo que si (y eso es un medio si) está usando node & Mongoose o una biblioteca de soporte con algunas sugerencias en el esquema, podría usar a.populate()
para buscar esos documentos:fuente
Tengo que estar en desacuerdo, podemos hacer que $ lookup funcione con la matriz de ID si lo precedimos con $ match stage.
Se vuelve más complicado si queremos pasar el resultado de la búsqueda a una canalización. Pero, de nuevo, hay una manera de hacerlo (ya sugerido por @ user12164):
fuente