2012-08-17 27 views
6

Los primeros experimentos con Spring Data y MongoDB fueron geniales. Ahora tengo la siguiente estructura (simplificada):Spring Data MongoDB: Accediendo y actualizando documentos secundarios

public class Letter { 
    @Id 
    private String id; 
    private List<Section> sections; 
} 

public class Section { 
    private String id; 
    private String content; 
} 

Cargar y guardar objetos Letter enteras/documentos funciona como un encanto. (Yo uso OBJECTID para generar identificadores únicos para el campo Section.id.)

Letter letter1 = mongoTemplate.findById(id, Letter.class) 
mongoTemplate.insert(letter2); 
mongoTemplate.save(letter3); 

Dado que los documentos son grandes (200K) y, a veces sólo sub-partes son necesarias por la aplicación: ¿Existe la posibilidad de consultar para una sub-documento (sección), modificar y guardarlo? me gustaría poner en práctica un método como

Section s = findLetterSection(letterId, sectionId); 
s.setText("blubb"); 
replaceLetterSection(letterId, sectionId, s); 

Y, por supuesto, como métodos:

addLetterSection(letterId, s); // add after last section 
insertLetterSection(letterId, sectionId, s); // insert before given section 
deleteLetterSection(letterId, sectionId); // delete given section 

veo que los últimos tres métodos son algo "extraño", es decir, la carga de todo el documento, modificando la recolección y el guardado de nuevo pueden ser el mejor enfoque desde un punto de vista orientado a objetos; pero el primer caso de uso ("navegar" a un subdocumento/subobjeto y trabajar en el alcance de este objeto) parece natural.

Creo que MongoDB puede actualizar los documentos secundarios, pero ¿se puede utilizar SpringData para el mapeo de objetos? Gracias por cualquier puntero.

Respuesta

12

Descubrí el siguiente enfoque para cortar y cargar solo un subobjeto. ¿Parece correcto? Soy consciente de los problemas con las modificaciones simultáneas.

Query query1 = Query.query(Criteria.where("_id").is(instance)); 
query1.fields().include("sections._id"); 
LetterInstance letter1 = mongoTemplate.findOne(query1, LetterInstance.class); 
LetterSection emptySection = letter1.findSectionById(sectionId); 
int index = letter1.getSections().indexOf(emptySection); 

Query query2 = Query.query(Criteria.where("_id").is(instance)); 
query2.fields().include("sections").slice("sections", index, 1); 
LetterInstance letter2 = mongoTemplate.findOne(query2, LetterInstance.class); 
LetterSection section = letter2.getSections().get(0); 

Esta es una solución alternativa que carga todas las secciones, pero omite los otros campos (grandes).

Query query = Query.query(Criteria.where("_id").is(instance)); 
query.fields().include("sections"); 
LetterInstance letter = mongoTemplate.findOne(query, LetterInstance.class); 
LetterSection section = letter.findSectionById(sectionId); 

Este es el código que utilizo para almacenar un solo elemento de la colección:

MongoConverter converter = mongoTemplate.getConverter(); 
DBObject newSectionRec = (DBObject)converter.convertToMongoType(newSection); 

Query query = Query.query(Criteria.where("_id").is(instance).and("sections._id").is(new ObjectId(newSection.getSectionId()))); 
Update update = new Update().set("sections.$", newSectionRec); 
mongoTemplate.updateFirst(query, update, LetterInstance.class); 

Es agradable ver cómo los datos de primavera se puede utilizar con "resultados parciales" de MongoDB.

Cualquier comentario muy apreciado!

+0

¿Puede compartir su método findSectionById() Implementación? –

+0

Me complace compartirlo, aunque es sencillo: simplemente pasa por las secciones de la carta y compara el campo ID. No tiene el código exacto aquí en este momento. –

Cuestiones relacionadas