2012-06-22 35 views
15

Digamos que tengo el siguiente esquema de documento en una colección llamada 'usuarios':MongoDB: ¿Consulta y recupera objetos dentro de una matriz incrustada?

{ 
    name: 'John', 
    items: [ {}, {}, {}, ... ] 
} 

La matriz 'artículos' contiene objetos en el siguiente formato:

{ 
    item_id: "1234", 
    name: "some item" 
} 

Cada usuario puede tener varios elementos incrustado en la matriz de 'elementos'.

Ahora, quiero poder obtener un elemento por un item_id para un usuario determinado.

Por ejemplo, quiero obtener el elemento con el id "1234" que pertenece al usuario con el nombre "John".

¿Puedo hacer esto con mongoDB? Me gustaría utilizar su poderosa indexación de matriz, pero no estoy seguro de si puede ejecutar consultas en matrices embebidas y devolver objetos desde la matriz en lugar del documento que la contiene.

Sé que puedo buscar usuarios que tienen un determinado artículo usando {users.items.item_id: "1234"}. Pero quiero buscar el elemento real de la matriz, no el usuario.

Como alternativa, ¿existe alguna forma mejor de organizar estos datos para que pueda obtener fácilmente lo que quiero? Todavía soy bastante nuevo para mongodb.

Gracias por cualquier ayuda o consejo que pueda proporcionar.

+0

posible duplicado de [MongoDB extraer sólo el elemento seleccionado en serie] (http: // stackoverflow.com/questions/3985214/mongodb-extract-only-the-selected-item-in-array) – Foreever

+0

Hola, @Nebs, ¿puedes revisar la respuesta aceptada y cambiarla? Porque hay una solución a este problema sin necesidad de dos colecciones separadas en versiones más nuevas de mongodb. –

Respuesta

22

La pregunta es antigua, pero la respuesta ha cambiado desde el momento. Con MongoDB> = 2.2, que puede hacer:

db.users.find({ name: "John"}, { items: { $elemMatch: { item_id: "1234" } } }) 

, dispondrá de:

{ 
    name: "John", 
    items: 
    [ 
     { 
     item_id: "1234", 
     name: "some item" 
     } 
    ] 
} 

See Documentation of $elemMatch

+2

Esta es la mejor respuesta a la pregunta del OP, espero que la vea y la modifique; de ​​lo contrario, muchas personas verán la respuesta aceptada y pensarán que no hay solución sin dos colecciones . –

1

Si se trata de una matriz incrustada, no podrá recuperar sus elementos directamente. El documento recuperado tendrá la forma de un usuario (documento raíz), aunque no todos los campos se pueden completar (dependiendo de su consulta).

Si desea recuperar solo ese elemento, debe almacenarlo como un documento separado en una colección separada. Tendrá un campo adicional, user_id (puede ser parte de _id). Entonces es trivial hacer lo que quieras.

Un documento de muestra podría tener este aspecto:

{ 
    _id: {user_id: ObjectId, item_id: "1234"}, 
    name: "some item" 
} 

Tenga en cuenta que esta estructura asegura la unicidad de item_id por usuario (no estoy seguro de que quieres esto o no).

+2

Gracias por la respuesta. Quería evitar usar dos colecciones para esto, pero parece que es la única forma. – nebs

6

Hay un par de cosas a tener en cuenta sobre esto:

1) me parece que lo más difícil para la gente de aprendizaje MongoDB es ONU-aprendizaje del pensamiento relacional que están acostumbrados. Su modelo de datos parece ser el correcto.

2) Normalmente, lo que haces con MongoDB es devolver todo el documento al programa cliente, y luego buscar la parte del documento que deseas del lado del cliente utilizando el lenguaje de programación de tu cliente.

En su ejemplo, debe buscar el documento completo de "usuario" y luego recorrer el conjunto de "elementos []" en el lado del cliente.

3) Si desea devolver solo la matriz 'items []', puede hacerlo utilizando la sintaxis 'Field Selection'. Vea http://www.mongodb.org/display/DOCS/Querying#Querying-FieldSelection para más detalles. Desafortunadamente, devolverá toda la matriz 'items []', y no solo un elemento de la matriz.

4) Existe un ticket Jira existente para agregar esta funcionalidad: es https://jira.mongodb.org/browse/SERVER-828 SERVER-828. Parece que se ha agregado a la última rama 2.1 (desarrollo): eso significa que estará disponible para el uso de producción cuando se envíe la versión 2.2.

+0

Esta es una respuesta fantástica. Espero que siga siendo relevante. –

Cuestiones relacionadas