Voici un simple pojo:
public class Description {
private String code;
private String name;
private String norwegian;
private String english;
}
Et consultez le code suivant pour appliquer un upsert
à MongoDb via Spring MongoTemplate:
Query query = new Query(Criteria.where("code").is(description.getCode()));
Update update = new Update().set("name", description.getName()).set("norwegian", description.getNorwegian()).set("english", description.getEnglish());
mongoTemplate.upsert(query, update, "descriptions");
La ligne pour générer l'objet Update
spécifie manuellement chaque champ de la classe Item
.
Mais si mon objet Item
change, ma couche Dao se casse.
Existe-t-il donc un moyen d'éviter cela, afin que tous les champs de ma classe Item
soient appliqués automatiquement à la mise à jour?
Par exemple.
Update update = new Update().fromObject(item);
Notez que mon pojo ne s'étend pas DBObject
.
J'ai rencontré le même problème. Dans la version actuelle de Spring Data MongoDB, rien de tel n'est disponible. Vous devez mettre à jour les champs séparés à la main.
Cependant c'est possible avec un autre framework: Morphia.
Ce framework a un wrapper pour la fonctionnalité DAO: https://github.com/mongodb/morphia/wiki/DAOSupport
Vous pouvez utiliser l'API DAO pour faire des choses comme ceci:
SomePojo pojo = daoInstance.findOne("some-field", "some-value");
pojo.setAProperty("changing this property");
daoInstance.save(pojo);
J'ai trouvé une assez bonne solution à cette question
//make a new description here
Description d = new Description();
d.setCode("no");
d.setName("norwegian");
d.setNorwegian("norwegian");
d.setEnglish("english");
//build query
Query query = new Query(Criteria.where("code").is(description.getCode()));
//build update
DBObject dbDoc = new BasicDBObject();
mongoTemplate.getConverter().write(d, dbDoc); //it is the one spring use for convertions.
Update update = Update.fromDBObject(dbDoc);
//run it!
mongoTemplate.upsert(query, update, "descriptions");
Veuillez noter que Update.fromDBObject renvoie un objet de mise à jour avec tous les champs dans dbDoc. Si vous souhaitez simplement mettre à jour les champs non nuls, vous devez coder une nouvelle méthode pour exclure les champs nuls.
Par exemple, le front-end publie un document comme ci-dessous:
//make a new description here
Description d = new Description();
d.setCode("no");
d.setEnglish("norwegian");
Il suffit de mettre à jour le champ 'langue':
//return Update object
public static Update fromDBObjectExcludeNullFields(DBObject object) {
Update update = new Update();
for (String key : object.keySet()) {
Object value = object.get(key);
if(value!=null){
update.set(key, value);
}
}
return update;
}
//build udpate
Update update = fromDBObjectExcludeNullFields(dbDoc);
La solution pour une nouvelle version Spring-data-mongodb 2.X.X.
L'API a évolué, depuis la version 2.X.X il y a:
Update.fromDocument(org.bson.Document object, String... exclude)
au lieu de (1.X.X):
Update.fromDBObject(com.mongodb.DBObject object, String... exclude)
La solution complète:
//make a new description here
Description d = new Description();
d.setCode("no");
d.setName("norwegian");
d.setNorwegian("norwegian");
d.setEnglish("english");
Query query = new Query(Criteria.where("code").is(description.getCode()));
Document doc = new Document(); // org.bson.Document
mongoTemplate.getConverter().write(item, doc);
Update update = Update.fromDocument(doc);
mongoTemplate.upsert(query, update, "descriptions");
Ça marche!
vous pouvez utiliser save: (si non exist = insert else = upsert)
save (Object objectToSave, String collectionName)
lire: javadoc
C'est ce que je fais pour le moment. Pas tellement une manière élégante de le faire, mais cela enregistre un précieux appel DB:
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.util.JSON;
/**
* Perform an upsert operation to update ALL FIELDS in an object using native mongo driver's methods
* since mongoTemplate's upsert method doesn't allow it
* @param upsertQuery
* @param object
* @param collectionName
*/
private void performUpsert(Query upsertQuery, Object object, String collectionName){
ObjectMapper mapper = new ObjectMapper();
try {
String jsonStr = mapper.writeValueAsString(object);
DB db = mongoTemplate.getDb();
DBCollection collection = db.getCollection(collectionName);
DBObject query = upsertQuery.getQueryObject();
DBObject update = new BasicDBObject("$set", JSON.parse(jsonStr));
collection.update(query, update, true, false);
} catch (IOException e) {
LOGGER.error("Unable to persist the metrics in DB. Error while parsing object: {}", e);
}
}
Si vous souhaitez ajouter Pojos incl. propriété String id;
vous devez exclure le champ _id dans la méthode fromDBObject Update.fromDBObject(dbDoc,"_id"
).
Sinon, vous obtenez l'exception:
org.springframework.dao.DuplicateKeyException: { "serverUsed" : "127.0.0.1:27017" , "ok" : 1 , "n" : 0 , "updatedExisting" : false , "err" : "E11000 duplicate key error collection: db.description index: _id_ dup key: { : null }" , "code" : 11000}; nested exception is com.mongodb.MongoException$DuplicateKey: { "serverUsed" : "127.0.0.1:27017" , "ok" : 1 , "n" : 0 , "updatedExisting" : false , "err" : "E11000 duplicate key error collection: db.description index: _id_ dup key: { : null }" , "code" : 11000}
car le champ _id du premier est nul
{
"_id" : null,
...
}
Le code complet basé sur la réponse @PaniniGelato serait
public class Description(){
public String id;
...
}
Description d = new Description();
d.setCode("no");
d.setName("norwegian");
d.setNorwegian("norwegian");
d.setEnglish("english");
//build query
Query query = new Query(Criteria.where("code").is(description.getCode()));
//build update
DBObject dbDoc = new BasicDBObject();
mongoTemplate.getConverter().write(d, dbDoc); //it is the one spring use for convertions.
Update update = Update.fromDBObject(dbDoc, "_id");
//run it!
mongoTemplate.upsert(query, update, "descriptions");
Ensuite, l'upsert fonctionne dans les cas d'insertion et mise à jour. Les corrections et réflexions sont les bienvenues;)
Il y a ici deux cas à distinguer:
Dans le cas 1), vous pouvez simplement utiliser mongoTemplate.save (pojo, "collection") , car votre POJO aura déjà un ObjectID rempli dans son champ id.
Dans le cas 2) Vous devez expliquer à mongo ce que "existe déjà" signifie dans le cas de votre modèle de domaine: Par défaut, la méthode mongoTemplate.save () met à jour un élément existant, s'il y en a un avec le même ObjectId. Mais avec un POJO nouvellement instancié, vous n'avez pas cet identifiant. Par conséquent, la méthode mongoTemplate.upsert () a un paramètre de requête que vous pouvez créer comme ceci:
MyDomainClass pojo = new MyDomainClass(...);
Query query = Query.query(Criteria.where("email").is("[email protected]"));
DBObject dbDoc = new BasicDBObject();
mongoTemplate.getConverter().write(pojo, dbDoc); //it is the one spring use for convertions.
dbDoc.removeField("_id"); // just to be sure to not create any duplicates
Update update = Update.fromDBObject(dbDoc);
WriteResult writeResult = mongoTemplate.upsert(query, update, UserModel.class);
Tout comme les réponses précédentes l'ont dit, utilisez les fonctions mongoTemplate.getConverter (). Write () et Update.fromDocument (). Mais j'ai trouvé Update.fromDocument () n'ajoutera pas la clé "$ set" et ne fonctionnera pas directement, la solution est d'ajouter vous-même "$ set", comme ci-dessous (PS: j'utilise la version 2.2.1.RELEASE ):
public static Update updateFromObject(Object object, MongoTemplate mongoTemplate) {
Document doc = new Document();
mongoTemplate.getConverter().write(object, doc);
return Update.fromDocument(new Document("$set", doc));
}
Utilisez simplement ReflectionDBObject
- si vous faites Description
l'étendre, vous devez simplement transférer les champs de votre objet vers Update
de manière réfléchie, automagiquement. La note ci-dessus sur les champs nuls inclus dans la mise à jour reste vraie.
@Override
public void updateInfo(UpdateObject algorithm) {
Document document = new Document();
mongoTemplate.getConverter().write(algorithm, document);
Update update = Update.fromDocument(document);
mongoTemplate.updateFirst(query(where("_id").is(algorithm.get_id())), update, UpdateObject.class);
}
public void saveOrUpdate(String json) {
try {
JSONObject jsonObject = new JSONObject(json);
DBObject update1 = new BasicDBObject("$set", JSON.parse(json));
mongoTemplate.getCollection("collectionName").update(new Query(Criteria.where("name").is(jsonObject.getString("name"))).getQueryObject(), update1, true, false);
} catch (Exception e) {
throw new GenericServiceException("Error while save/udpate. Error msg: " + e.getMessage(), e);
}
}
c'est un moyen très simple d'enregistrer une chaîne json dans une collection en utilisant mongodb et spring. Cette méthode peut être remplacée pour être utilisée comme JSONObject.
Je pense que: Description ajouter une propriété
@Id
private String id;
puis obtenez un document par la condition de requête, définissez l'ID de la description par l'ID du document. Et enregistrer