updating a value in an array in mongodb from java

懵懂的女人 提交于 2020-01-14 06:07:02

问题


I have couple of documens in mongodb as follow:

{
"_id" : ObjectId("54901212f315dce7077204af"),
"Date" : ISODate("2014-10-20T04:00:00.000Z"),
"Type" : "Twitter",
"Entities" : [ 
    {
        "ID" : 4,
        "Name" : "test1",
        "Sentiment" : {
            "Value" : 20,
            "Neutral" : 1
        }
    },
    {
        "ID" : 5,
        "Name" : "test5",
        "Sentiment" : {
            "Value" : 10,
            "Neutral" : 1
        }
    }
]

}

Now I want to update the document that has Entities.ID=4 by adding (Sentiment.Value+4)/2 for example in the above example after update we have 12.

I wrote the following code but I am stuck in the if statement as you can see:

 DBCollection collectionG;
   collectionG = db.getCollection("GraphDataCollection");
    int entityID = 4;
    String entityName = "test";
    BasicDBObject queryingObject = new BasicDBObject();
    queryingObject.put("Entities.ID", entityID);
    DBCursor cursor = collectionG.find(queryingObject);

    if (cursor.hasNext())
    {
        BasicDBObject existingDocument = new BasicDBObject("Entities.ID", entityID);
        //not sure how to update the sentiment.value for entityid=4
    }

First I thought I should unwind the Entities array first to get the value of sentiment but if I do that then how can I wind them again and update the document with the same format as it has now but with the new sentiment value ?

also I found the this link as well : MongoDB - Update objects in a document's array (nested updating)

but I could not understand it since it is not written in java query, can anyone explain how I can do this in java?


回答1:


You need to do this in two steps:

  • Get all the _id of the records which contain a Entity with sentiment value 4.
  • During the find, project only the entity sub document that has matched the query, so that we can process it to consume only its Sentiment.Value. Use the positional operator($) for this purpose.
  • Instead of hitting the database every time to update each matched record, use the Bulk API, to queue up the updates and execute it finally.

Create the Bulk operation Writer:

    BulkWriteOperation bulk = col.initializeUnorderedBulkOperation();

Find all the records which contain the value 4 in its Entities.ID field. When you match documents against this query, you would get the whole document returned. But we do not want the whole document, we would like to have only the document's _id, so that we can update the same document using it, and the Entity element in the document that has its value as 4. There may be n other Entity documents, but they do not matter. So to get only the Entity element that matches the query we use the positional operator $.

    DBObject find = new BasicDBObject("Entities.ID",4);
    DBObject project = new BasicDBObject("Entities.$",1);
    DBCursor cursor = col.find(find, project);

What the above could would return is the below document for example(since our example assumes only a single input document). If you notice, it contains only one Entity element that has matched our query.

{
        "_id" : ObjectId("54901212f315dce7077204af"),
        "Entities" : [
                {
                        "ID" : 4,
                        "Name" : "test1",
                        "Sentiment" : {
                                "Value" : 12,
                                "Neutral" : 1
                        }
                }
        ]
}

Iterate each record to queue up for update:

    while(cursor.hasNext()){
        BasicDBObject doc = (BasicDBObject)cursor.next();
        int curVal = ((BasicDBObject)
                     ((BasicDBObject)((BasicDBList)doc.get("Entities")).
                     get(0)).get("Sentiment")).getInt("Value");
        int updatedValue = (curVal+4)/2;
        DBObject query = new BasicDBObject("_id",doc.get("_id"))
                         .append("Entities.ID",4);
        DBObject update = new BasicDBObject("$set",
                          new BasicDBObject("Entities.$.Sentiment.Value",
                                             updatedValue));
        bulk.find(query).update(update);
    }

Finally Update:

    bulk.execute();

You need to do a find() and update() and not simply an update, because currently mongodb does not allow to reference a document field to retrieve its value, modify it and update it with a computed value, in a single update query.



来源:https://stackoverflow.com/questions/27831974/updating-a-value-in-an-array-in-mongodb-from-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!