Using $function in updateMany not working

I have an array tree and I want to update that array in my collection with this syntax

db.documents.updateMany(
  {
    companyId: ObjectId("5f29074048538b6403bc71ab",
    tree: {
      $in: [ObjectId("5f539bf696fa1748fa417b07")],
    },
  },
  {
    $set: {
      tree: {
        $function: {
          body:
            "function(t) { t.push(ObjectId('5f5494a1d708bda4988d75d4')); return t.filter(v => [ObjectId('5f539bf696fa1748fa417b07')].includes(v))}}",
          args: ["$tree"],
          lang: "js",
        },
      },
    },
  }
);

why I write body function with string? because in Golang I can’t use code for bson, so I must use function , the syntax above is I run on command line mongo cli to try there first then implement to my Go app

the error I got is

The dollar ($) prefixed field '$function' in 'tree.$function' is not valid for storage

anyone has same problem ? or I did wrong to use $function operator ??

Hello : )

The function operator requires mongodb 4.4,and it is an aggregation operator.
To use it on update,you have to use a pipeline,and aggregation operators.
(you use the $set update operator,not the $set($addField) aggregation operator)
Also to use the pipepile,your driver must support mongodb >= 4.2,and provide
a update method to accept a pipeline as argument.

Pipeline updates are different,but here looks like that just adding a [ ]
in the update part will work,if your driver supports it.

1 Like

I am using Mongo Atlas and I am sure it gonna valid for using $function, and in my mongo cli I login as username on Mongo Atlas, can u give me example for update query with $function ? because the example on documentation only for query find data ,? @Takis

Hello

This updated the documents where $mystring=“a”,and to “a Updated”.
Using the $function,i runned it on mongo shell

> use testdb
switched to db testdb
> db.testcoll.drop()
true
> db.testcoll.insert([{"_id":1,"mystring":"a"},{"_id":2,"mystring":"b"},{"_id":3,"mystring":"c"},{"_id":4,"mystring":"a"}]);
BulkWriteResult({
	"writeErrors" : [ ],
	"writeConcernErrors" : [ ],
	"nInserted" : 4,
	"nUpserted" : 0,
	"nMatched" : 0,
	"nModified" : 0,
	"nRemoved" : 0,
	"upserted" : [ ]
})
> db.testcoll.find();
{ "_id" : 1, "mystring" : "a" }
{ "_id" : 2, "mystring" : "b" }
{ "_id" : 3, "mystring" : "c" }
{ "_id" : 4, "mystring" : "a" }
> db.testcoll.updateMany({"mystring" : "a"},[{"$addFields":{"mystring":{"$function":{"args":["$mystring"],"lang":"js","body":"function mypush(s) {  return s+\" Updated\";}"}}}}]);
{ "acknowledged" : true, "matchedCount" : 2, "modifiedCount" : 2 }
> 
> db.testcoll.find();
{ "_id" : 1, "mystring" : "a Updated" }
{ "_id" : 2, "mystring" : "b" }
{ "_id" : 3, "mystring" : "c" }
{ "_id" : 4, "mystring" : "a Updated" }

I tested on updating array also,its the same way,it worked fine,i used push.
This is how it works,but pipeline update are different from the old updates way.
With pipeline the result of the pipeline is the new document you want.

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.