Mongo Update Specific Elements of an Array of Documents

Can not update data.

db.getCollection('doubles').update({'_id': ObjectId("5b5cd567264c1c66724f593c") }, {
                $set: {'contacts.$[i_contact].name': 'HELLO WORLD'}
            },
            {
                multi: true,
                arrayFilters: [
                    {"i_contact.id": {$eq: 32872580}},
                ]
            })

Error: No array filter found for identifier ‘i_contact’ in path ‘contacts.$[i_contact].name’
In “Meteor” is also the most error.

Please help!
Scr:

db.getCollection('doubles').update(
       {'_id': ObjectId("5b5cd567264c1c66724f593c"), 
        'contacts.id': 32872580 
       }, {
          $set: {'contacts.$.name': 'HELLO WORLD'}
       }, {
          multi: true
       }
)

https://docs.mongodb.com/manual/reference/operator/update/positional/#examples

Thanks for your reply! Your example works. My final task is more complicated, I wanted to understand by a simple example.

Apparently this principle is not suitable for a complex query:

db.getCollection('doubles').update(
       {'_id': ObjectId("5b5cd567264c1c66724f593c"), 
        'contacts.id': 32872580,
        'contacts.custom_fields.id': 340354, 
        'contacts.custom_fields.values.value': '79045155956'
       }, {
          $set: {'contacts.$.custom_fields.$.values.$.mergeUnSelect': true}
       }, {
          multi: true
       }
)

Error: Too many positional (i.e. ‘$’) elements found in path ‘contacts.$.custom_fields.$.values.$.mergeUnSelect’

:tired_face:


Yes, you cannot do nested arrays with this. Only one $ is allowed.

That you’ll have to achieve programmatically - with foreach and the like.

I found out that the meteor does not support such an update. From the terminal the command is executed, from the meteor - gives an error. It turns out that the meteor does not have correct support for Mongo 3.6?

I don’t think you’ll be able to do nested array updates using Meteor’s minimongo. You should be able to do it on the server by using the underlying MongoDB npm update method.

SomeCollection.rawCollection().update(...);

However, your syntax for nested arrays is not correct. Check the MongoDB docs here.

DoublesCol.rawCollection().update({_id: ObjectIdDoublesGroupId}, {
                $set: {'contacts.$[icontact].custom_fields.$[icf].values.$[icfv].enum': 'My TEXT!'}
            },
            {
                arrayFilters: [
                    {"icontact.id": {$eq: essenceId}},
                    {"icf.id": {$eq: customFieldId}},
                    {"icfv.value": {$eq: customFieldValue}},
                ],
                multi: true
            });

Now there is no error, but the data is not updated.
Can you tell us what the error is? I’m already just getting f*** with this meteor, I can not solve the problem 3 day.

Does this same query work in the Mongo console?

I suspect you are discarding the error, because you are using the non-callback form of the update method, which returns a Promise. You should:

  • Use a Promise chain with a catch() to complete the chain, or:
  • Use async/await and wrap the update call in a try/catch, or:
  • Use the callback form if you don’t need a Fiber in the callback, or:
  • Use the callback form wrapped in Meteor.wrapAsync.

and at least console.log the error.

1 Like

Thanks for the answer! I continue to struggle with the meteor. I found one more problem, he does not search for “ObjectID”, according to the available information on the web, the search / update for “ObjectID” is unsuccessful.

ObjectIdDoublesGroupId - is Meteor.Collection.ObjectID:
successful check: "

check(ObjectIdDoublesGroupId, Meteor.Collection.ObjectID); "


does not work:

DoublesCol.rawCollection().findOne({_id: ObjectIdDoublesGroupId});

result: null

  1. does not work:
var oid  = new Meteor.Collection.ObjectID("5b60122d86e9c706c6fd8263");
DoublesCol.rawCollection().findOne({_id: oid});

result: null

  1. Find in Robo 3T successful:
    https://yadi.sk/i/w30DjB7E3Zkgo6

There are a couple of issues there:

  1. You are using very old (deprecated) syntax. The syntax should be:

    var oid = new Mongo.ObjectID("5b60122d86e9c706c6fd8263");
    

    Although, it will return the exact same result as yours. However, it makes me wonder where you are getting your Meteor code guide from? It could be that you are using some very old coding standard, which is causing some of your issues.

  2. The real problem is that once again, you are using the Promise form of the method and not waiting/discarding the result. Try changing that part to the standard Meteor form:

    var oid = new Mongo.ObjectID("5b60122d86e9c706c6fd8263");
    var result = DoublesCol.findOne(oid);
    console.log(result);
    

Alternatively, follow the same 4 steps I mentioned earlier to work with Promises.

I tried to use Promis and “new Mongo.ObjectID”. The result is “null”. The meteor has no documentation at all, it is very difficult to work with it. The solution of a simple task takes days …

Meteor.methods({
async 'updateDoublesCustomFieldsAutoMerge'(ObjectIdDoublesGroupId, essenceId, customFieldId, customFieldValue){
        const oid = new Mongo.ObjectID("5b60122d86e9c706c6fd8263");
        return await DoublesCol.rawCollection()
            .findOne({_id: oid});
    },
});

call:

const item = Meteor.call('updateDoublesCustomFieldsAutoMerge', ObjectIdDoublesGroupId, essenceId, customFieldId, customFieldValue);

console.log(item);

The result is “null”.

for the sake of experiment:

async 'updateDoublesCustomFieldsAutoMerge'(ObjectIdDoublesGroupId, essenceId, customFieldId, customFieldValue){
        const oid = new Mongo.ObjectID("5b60122d86e9c706c6fd8263");
        return await DoublesCol.rawCollection()
            .find({_id: oid}).count();
    },

result: 0 ( https://yadi.sk/i/nlHP1-ci3ZmQhC )

async 'updateDoublesCustomFieldsAutoMerge'(ObjectIdDoublesGroupId, essenceId, customFieldId, customFieldValue){
        return await DoublesCol.rawCollection()
            .find().count();
    },

result: 2335 ( https://yadi.sk/i/0kwofna43ZmQbC )

async 'updateDoublesCustomFieldsAutoMerge'(ObjectIdDoublesGroupId, essenceId, customFieldId, customFieldValue){
        const oid = new Mongo.ObjectID("5b60122d86e9c706c6fd8263");
        return await DoublesCol.rawCollection()
            .find({'value': '79214019711'}).count();
    },

Result: 1 ( https://yadi.sk/i/bx0JHFch3ZmRAr )

async 'updateDoublesCustomFieldsAutoMerge'(ObjectIdDoublesGroupId, essenceId, customFieldId, customFieldValue){
        const oid = new Mongo.ObjectID("5b60122d86e9c706c6fd8263");
        return DoublesCol
            .find({'_id': oid}).count();
    },

Result 1 ( https://yadi.sk/i/9gGxOlty3ZmRSn )

5

async 'updateDoublesCustomFieldsAutoMerge'(ObjectIdDoublesGroupId, essenceId, customFieldId, customFieldValue){
        return await DoublesCol
            .find({'_id': ObjectIdDoublesGroupId}).count();
    },

Result 1 ( https://yadi.sk/i/X8WrIzco3ZmRpy )

TOTAL:
Experimentally, it was found that the rawCollection does not search for “Mongo.ObjectID”

Please help to solve the problem!

Do you have a repo demonstrating the issue?

I uploaded the demo project to the bitbucket:
https://bitbucket.org/atomdigital/test/src
it demonstrates that “rawCollection” does not work with “ObjectID”.
( Img project: https://yadi.sk/i/L92nIUOb3ZoRJT )

Decided to abandon the “ObjectID”, began to use “_id: Random.id()”.

On request:

Meteor.methods({
    async 'updateDoublesCustomFieldsAutoMerge'(doublesGroupId, essenceId, customFieldId, customFieldValue) {

        const result  = await DoublesCol.rawCollection().update(
            {_id: doublesGroupId}, {
                $set: {'contacts.$[icontact].custom_fields.$[icf].values.$[icfv].enum': 'My TEXT!'}
            },
            {
                arrayFilters: [
                    {"icontact.id": {$eq: essenceId}},
                    {"icf.id": {$eq: customFieldId}},
                    {"icfv.value": {$eq: customFieldValue}},
                ],
                multi: true
            });

        return result;
    },

})

Call method:

Meteor.call('updateDoublesCustomFieldsAutoMerge', doublesGroupId, essenceId, customFieldId, customFieldValue);

An error occurs:
Exception while invoking method ‘doubles.checkCustomFieldsAutoMerge’ RangeError: Maximum call stack size exceeded

But, at the same time he has time to update the data …

error “RangeError: Maximum call stack size exceeded” execution in the terminal of the command:

export TOOL_NODE_FLAGS="–max_old_space_size=4096"

did not help

eventually solved the problem with the help of “manual busting”:

let doublesGroup = DoublesCol.findOne({accountId: +accountId, _id: doublesGroupId});
        
        let doublesContact = doublesGroup.contacts
            .filter(fc => fc.id === essenceId)
            .map(contact => {
                contact.custom_fields.map(cf => {

                        if (cf.id == customFieldId && _.isArray(cf.values) && cf.values.length > 0) {

                            cf.values.map(cfv => {
                                if (cfv.value == customFieldValue) {

                                    if (checked) {
                                        if (cfv.excluded) delete cfv.excluded;
                                    } else {
                                        cfv.excluded = true;
                                    }
                                }
                                return cfv;
                            })

                        }
                        return cf;
                    }
                );
                return contact;
            });

        console.log(doublesContact);

        DoublesCol.update({accountId: +accountId, _id: doublesGroupId, 'contacts.id': essenceId}, {
            $set: {'contacts.$': doublesContact[0]}
        });