JamesC
JamesC

Reputation: 496

MongoDB updating an array element in a specific index using the Java driver

Usually, I avoid asking a new question as I always find a "close-enough" answer to my problem.

But this time I surprisingly have a fundamental and straightforward question - without any lead.

I have a straightforward MongoDB document that holds two arrays:

For example, let's say subject code 12 is - "What's your 1st dog's name?", and the user's answer was: "Spiky", etc...

So I end up with something like:

    {
        "_id" : ObjectId("..."),
        "questionCodesArray" : [
                12,
                56,
                3
            ],
        "answersArray" : [
                "Spiky",
                "go swimming",
                "blabla.."
            ]
    }

Now, I'd like to be able to allow the users to change their mind and choose a different question and supply a different answer to it.

For this, I need to have only the index of my element and access it via this index to change it using update() or findAndModify() [or any other method] and all the answers out there are "key-value style" which is not needed.

In simple Java I would've simply done something like:

questionsCodesArry[index] = newValue; and answersArray[index] = newAnswerString;

All my attempts to write a descent query to do this simple index-based updating have failed.

Any help will be appreciated.

Thank you.

Upvotes: 1

Views: 2452

Answers (2)

JamesC
JamesC

Reputation: 496

Well, after some trials here is a c&p complete and full method to change an array's element by a given index:

public boolean changeArrayValue(DB db, String collectionName, long id, String arrayNameKey, int index, Object newValue)
{
    DBCollection collection = db.getCollection(collectionName);
    DBObject query          = new BasicDBObject("id",id);//unique id is recommended
    DBObject update         = new BasicDBObject("$set", new BasicDBObject(arrayNameKey+"."+index, newValue));

    DBObject result = collection.findAndModify(query, null, null, false, update,true, true);

    //Just for precaution
    if(result == null)
        return false;

    return (((BasicDBList)result.get(arrayNameKey)).get(index)).equals(newValue);
}

As you can see the main issue lays in the $set line here: arrayNameKey+"."+index .

In the result I've put the needed flags to get the updated result, which is of type BasicDBList<Object>.

Pleases note that you'll have to add all the needed checks and validations according to your taste. Enjoy..

Upvotes: 0

dnickless
dnickless

Reputation: 10918

In plain MongoDB syntax what you need is this:

collection.update({
    /*your filter goes here*/
}, {
    $set: {
        "questionCodesArray.<zero-based-index>": "new value"
    }
})

I don't have a Java environment here to translate this into your driver's world. I might be able to do so tonight, though.

Still, I would definitely vote for a different, more natural and less error-prone design where you'd structure your data like so:

{
    "_id" : ObjectId("59b635ffad44fad6662d8591"),
    "answers" : [ 
        {
            "questionCode" : 12,
            "answer" : "Spiky"
        }, 
        {
            "questionCode" : 56,
            "answer" : "go swimming"
        }, 
        {
            "questionCode" : 3,
            "answer" : "blabla.."
        }
    ]
}

If that's an option for you I shall happily provide you the right update statement for this layout, too.

Upvotes: 2

Related Questions