1

Subdishes is a array in the item MajorFood. I want to add subdishes if they don't exist and update the subdishes if they do exist.

I tried the update method with addToSet. This works fine for a normal element but fails for an array.

                MajorFood.update({'_id' : majorFoodId, 'subdishes.food' : rowVals[0]},
                {$addToSet : {subdishes : {
                    food : rowVals[0],
                    energy : {
                        calories : s.getIntVal(rowVals[1]),
                        unit : rowVals[2]
                    }           
                }}}, {upsert : true}, function(err, doc){
                if(err){
                    s.l("err update" );
                    callback(err);
                    return;
                }
                s.l("success");
                callback(); 
            });

The update works fine when the value food already exists in subdishes. But it crashes when an element has to be added to the array.

I am getting the following error:

MongoError: Cannot apply $addToSet to a non-array field. 
Field named 'subdishes' has a non-array type Object

Is there a method to do this in a single function?

3
  • Have you read the error message? There are documents in your collection where subdishes is not an array as you expect. Commented Dec 29, 2016 at 12:11
  • you can use $cond operator to check if field exist (with $exist) or it's type (with $type) and then use $addToSet or not Commented Dec 29, 2016 at 12:18
  • @felix, subdishes: {$type: 'object'} will resolve to true in both cases, when subdishes is an object and when it is an array of objects: docs.mongodb.com/manual/reference/operator/query/type/#arrays Commented Dec 29, 2016 at 12:39

2 Answers 2

1

You won't be able to do this with a single atomic update. You can use the callback in the update function to check if there has been an update and push to array if not since the document does not exist:

MajorFood.update(
    { 
        "_id": majorFoodId,
        "subdishes.food" : rowVals[0]
    },
    { 
        "$set": {
            "subdishes.$": {        
                //without $ you get the error The dotted field is not valid for storage     
                "energy.$.calories": s.getIntVal(rowVals[1]),
                "energy.$.unit": rowVals[2]
            } 
       }
    },
    function(err, numAffected, rawResponse) {
        console.log(numAffected);
        console.log(rawResponse);
        if (!numAffected) {
            /* Push to array if subdish doesn't exist hence there's no update */
            MajorFood.update(
                { "_id": majorFoodId }
                { 
                    "$push": { 
                        "subdishes": {
                            "food": rowVals[0],
                            "energy": {
                                "calories": s.getIntVal(rowVals[1]),
                                "unit": rowVals[2]
                            } 
                        }
                    }
                },
                function(err, numAffected) {
                    if(err){
                        s.l("err update" );
                        callback(err);
                        return;
                    }
                    s.l("success");
                    callback(); 
                }
            );
        }            

    }
);
Sign up to request clarification or add additional context in comments.

1 Comment

This would be my backup method. I didn't want to repeat the codes for the push and the set parts.
0

May be this link can help you : mongodb addToSet a non-array field

   MajorFood.update({'_id' : majorFoodId, 'subdishes.food' : {$in:[rowVals[0]]}},
            {$addToSet : {subdishes : {
                food : rowVals[0],
                energy : {
                    calories : s.getIntVal(rowVals[1]),
                    unit : rowVals[2]
                }           
            }}}, {upsert : true}, function(err, doc){
            if(err){
                s.l("err update" );
                callback(err);
                return;
            }
            s.l("success");
            callback(); 
        });

3 Comments

I am getting this error: E11000 duplicate key error collection: appdb.food index: _id_ dup key: { : ObjectId(\'5865076b8bd0fc2a900324fc\') }'
I deleted every document in the collection and I still get this error
this error comes because you have a record with (_id : majorFoodId) but (subdishes.food not equal to rowVals[0]). so it try to insert the record with same _id and throw the error

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.