2012-06-29 14 views
16

Tengo una pregunta sobre MongoDB con Spring Data. tengo estas clases de dominio:MongoDB Embedded Objects no tiene ID (valor nulo)

@Document 
public class Deal { 
    @Id 
    private ObjectId _id; 
    private Location location; 
    private User user; 
    private String description; 
    private String title; 
    private String price; 
    private boolean approved; 
    private Date expirationDate; 
    private Date publishedDate; 
} 

@Document 
public class Location { 
    @Id 
    private ObjectId _id; 
    private Double latitude; 
    private Double longitude; 
    private String country; 
    private String street; 
    private String zip; 
} 

@Document 
public class User { 
    @Id 
    private ObjectId _id; 
    private String email; 
    private String password; 
    private String profile_image_url; 
    private Collection<Deal> deals = new ArrayList<Deal>(); 
} 

Con estos dominios que puedo con éxito CRUD. Solo hay un problema. Al guardar un Usuario con Ofertas, las ofertas y la Ubicación obtienen _id establecido en nulo al guardarlos en MongoDB. ¿Por qué no puede MongoDB generar identificaciones únicas para objetos incrustados?

El resultado después de guardar un usuario con un trato:

{ "_id" : ObjectId("4fed0591d17011868cf9c982"), 
    "_class" : "User", 
    "email" : "[email protected]", 
    "password" : "mimi", 
    "deals" : [ 
    { "_id" : null, 
     "location" : { "_id" : null, 
     "latitude" : 2.22, 
     "longitude" : 3.23445, 
     "country" : "Denmark", 
     "street" : "Denmark road 77", 
     "zip" : "2933" }, 
     "description" : "The new Nexus 7 Tablet. A 7 inch tablet from Google.", 
     "title" : "Nexus 7", 
     "price" : "1300", 
     "approved" : false, 
     "expirationDate" : Date(1343512800000), 
     "publishedDate" : Date(1340933521374) } ] } 

Como se puede ver en el resultado, Deal y el ID de ubicación se establece en NULL.

+0

Una ID identifica un documento raíz, no documentos secundarios. No hay ninguna razón por la que desee generar automáticamente una identificación para un documento anidado, ya que MongoDB solo puede recuperar documentos de primer nivel. ¿Para qué necesitas realmente la identificación anidada? –

+0

Necesito buscar solo ofertas y no Usuario. Ahora tengo que buscar desde el usuario y luego el bucle lanzó cada trato en el usuario mediante programación. – Millad

+0

La identificación no tiene nada que ver con lo que puede buscar. Está perfectamente bien buscar '{'deals.price': {$ gt: 1000}}'. Aún así, esta consulta devolvería un objeto 'Usuario' que manualmente tendría que sacar el' Deal' de entonces. Esta es una limitación de MongoDB, nada implícito en Spring Data. –

Respuesta

4

Un _id no está configurado en los subdocumentos de forma predeterminada solo en los archivos raíz.

Deberá definir un _id para sus subdocumentos al insertar y actualizar.

+0

¿No debería él hacer eso por mí? ¿Cómo puedo hacer eso? ¿Debo insertar cada documento solo y ponerlos juntos? Así es como inserto: mongoOperation.insert (deal); – Millad

+0

MongoDB no hará esto por usted, pero ahora que echo un segundo vistazo, tal vez su Conductor debería ... ¿está usando Morphia? – Sammaye

+0

gracias por las respuestas. Estoy usando Spring Data y mongo-java-driver. Cuando busco ofertas obtengo un objeto Usuario. No puedo buscar usando Deals. Tengo que ir a lanzar User y luego consultar programáticamente en User para ofertas. – Millad

29

operaciones CRUD (MongoDB insert, update, find, remove) todos funcionan en documentos de alto nivel exclusivamente - aunque por supuesto se puede filtrar por campos en documentos incrustados. Los documentos incrustados siempre se devuelven dentro del documento principal.

El campo _id es un campo obligatorio del documento principal y, por lo general, no es necesario ni está presente en los documentos incrustados. Si necesita un identificador único, puede crearlos y puede usar el campo _id para almacenarlos si es conveniente para su código o su modelo mental; más típicamente, se nombran según lo que representan (por ejemplo, "nombre de usuario", "otherSystemKey", etc.). Ni MongoDB ni ninguno de los controladores llenarán automáticamente un campo _id excepto en el documento de nivel superior.

Específicamente en Java, si desea generar valores para el campo OBJECTID _id en los documentos incorporados, puede hacerlo con:

someEmbeddedDoc._id = new ObjectId(); 
+0

Gracias por aclarar esto. Por lo tanto, si quiero hacer una lista de ofertas solo, debo separar o mover el documento de usuario del documento de oferta para que Deal sea un documento separado y User es un documento separado y luego consulta. – Millad

+0

O eso o ajuste su código para trabajar con el modelo de datos existente. Si con frecuencia está manipulando ofertas, o si las ofertas están asociadas con más de un usuario, entonces la normalización del modelo de datos puede tener sentido. – dcrosta

2

Mongo no crea ni necesita _id s en documentos incrustados. Puede agregar un campo _id si lo desea; lo he hecho.

@Document 
public class Location { 
    @Id 
    private ObjectId _id; 

    public Location() { 
     this._id = ObjectId.get(); 
    } 
} 

@Document 
public class User { 
    @Id 
    private ObjectId _id; 

    public User() { 
     this._id = ObjectId.get(); 
    } 
} 

Esto funciona muy bien para mí.

4

En el contexto de una arquitectura REST tiene todo el sentido de que los documentos anidados tienen sus propios Id.

  1. La implementación de la persistencia debe ser independiente de la representación de los recursos. Como consumidor API, no me importa si está usando mongo o mysql. Si anida documentos sin id en mongo, intente imaginar cómo cambiar la capa de persistencia a una base de datos relacional. Ahora haga el mismo ejercicio habiendo pensado de antemano con un enfoque independiente de la implementación. Al modelar documentos anidados en un db relacional, los documentos raíz y anidados serán entidades/tablas diferentes, cada una con sus propios identificadores. La raíz podría tener una relación uno a muchos con el documento anidado.
  2. Es posible que necesite acceder a un documento anidado directamente en lugar de secuencialmente. Puede que no necesite identificadores únicos absolutos, como los emitidos por mongo, pero aún necesitaré algún identificador único local. Esto es único en el documento raíz.

Habiendo discutido mi punto sobre la necesidad de identificadores en documentos anidados @dcrosta ya ha dado una respuesta correcta sobre cómo llenar el campo _id en mongo.

Espero que esto ayude.