Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove an array entry in an object using spring data mongodb

I recently spent some time trying to use the $pull operator through Spring's Data MongoOperations interface, so I thought it would be nice to share my findings in case anyone bumps into a similar problem.

So here it goes...

I have 2 java POJOs like so :

@Document
public class OutterObject{

    private String id;
    private String name;
    private List<InnerDocument> innerDocs;


    //SETTERS - GETTERS Ommited


public class InnerDocument{


    private String id;
    private String name;

         //SETTERS - GETTERS Ommited

This is stored in a Mongo collection like so :

 "_id" : "doc2",
 "_class" : "OutterObject",
 "name" : "doc2",
 "innerDocs" : [{
      "_id" : "innerDoc21",
      "name" : "innerDoc21"
  }, {
      "_id" : "innerDoc22",
      "name" : "innerDoc22"
  }]

I'm trying to use the $pull operator in order to remove all objects inside the innerDoc collection having a name value = "innerDoc22".

I know how to accomplish this using the mongo driver like so :

 List<String> ids = 
         Arrays.asList("innerDoc22");

 BasicDBObject find = new BasicDBObject();

 match.put("innerDocs.name", 
           BasicDBObjectBuilder.start("$in", ids).get());

    BasicDBObject update = new BasicDBObject();
        update.put(
                "$pull",
                BasicDBObjectBuilder.start("innerDocs",
                        BasicDBObjectBuilder.start("name", "innerDoc22").get()).get());

  DBCollection col= mongoOperations.getDb().getCollection("outterObject");

  col.update(find , update);

I'm trying to accomplish the same thing using Spring's MongoOperations Interface. Here is my code using the MongoOperations interface :

List<String> ids = Arrays.asList("innerDoc22");

Query removeQuery = Query.query(Criteria.where("innerDocs.name").in(ids));

WriteResult wc = mongoOperations.upsert(
                    removeQuery, 
                    new Update().pull("innerDocs.name", "innerDoc22"), 
                    OutterObject.class);
System.out.println(wc.getLastError());

I'm not getting any errors when calling getLastError() the update is simply not done in the database.

I know a similar question has already been asked here but the answer that was given does not use the MongoOperations interface.

like image 724
ufasoli Avatar asked Aug 21 '12 11:08

ufasoli


People also ask

How do I remove an entry from an array in MongoDB?

To remove an element, update, and use $pull in MongoDB. The $pull operator removes from an existing array all instances of a value or values that match a specified condition.

Can I use Spring data JPA with MongoDB?

Yes, DataNucleus JPA allows it, as well as to many other databases. You make compromises by using the JPA API for other types of datastores, but it makes it easy to investigate them.

How does spring boot store JSON objects in MongoDB?

To store raw json object/array, all you have to do is to declare the type as "Object" in the Pojo and/or DTO level on your server side. The "Object" type will work with Spring Data and MapStruct too. Then on the client side, you can send your json data as a json data.

Can we connect MongoDB with spring boot?

We need following APIs to work with Spring Boot and MongoDB database. There are two approaches through which we can connect to MongoDB database - MongoRepository and MongoTemplate . We will try to establish what one API offers over another and when should you choose any one of them for your use-case.


2 Answers

After searching a bit and looking at the source code I realized that I needed to pass an InnerDocument object as a second parameter to the pull method so that the spring classes would be able to do the mapping correctly.

As it turns out I can navigate objects while selecting objects (I'm using "innerDocs.name" in the removeQuery) but I cannot (or havent found a way) do the same when updating a document.

Below is how I implemented the query using MongoOperations :

List<String> ids = Arrays.asList("innerDoc22", "innerDoc21");

Query removeQuery = Query.query(Criteria.where("innerDocs.name").in(ids));

WriteResult wc = 
       mongoOperations.upsert(removeQuery, 
           new Update().pull("innerDocs", 
           new InnerDocument("innerDoc22", null)), 
           OutterObject.class);

System.out.println(wc.getLastError());
like image 81
ufasoli Avatar answered Nov 15 '22 04:11

ufasoli


You can also use the BasicDBObject instead of the InnerDocument I found this out by accident. By printing out the update object, you can see the actual mongo shell query json, which is super helpful for debugging. :

Update updateObj = new Update()
         .pull("innerDocs", new BasicDBObject("innerDocs.name","innerDoc22"));

System.out.println("UPDATE OBJ: " + updateObj.toString());

results in:

UPDATE OBJ: { "$pull" : { "innerDocs" : { "innerDocs.name" : "innerDoc22"}}}

like image 22
med116 Avatar answered Nov 15 '22 03:11

med116