1

I'm not 100% percent if this is possible, but i think it should be.

I want to update a document so that a field (END) is inserted into an array (INTERMISSIONS). I think im quite close to achieving it, but i either get an error or insert the string "$END".

The two queries i have are :

db.myCollection.findOneAndUpdate(
    {"_id" : new ObjectId("...")}, 
    { '$push' : {'INTERMISSIONS' : '$END' } }
)

This one completes without errors, but instead of the $END value just "$END" is inserted

db.myCollection.findOneAndUpdate(
    {"_id" : new ObjectId("...")}, 
    { '$push' : 
        {'INTERMISSIONS' : {$first:"$END" }}
    }
)

Here i tried to "force" mongo to recognise $END as a field, but i instead get the error The dollar ($) prefixed field '$first' in 'INTERMISSIONS..START.$first' is not valid for storage.

The document structure is the following

{ 
    "_id" : ObjectId("5f7dabb9c02c0000d2003ec2"), 
    "USUARIO" : "admin", 
    "START" : ISODate("2020-10-07T11:51:21Z"), 
    "INTERMISSIONS" : [ ], 
    "END" : ISODate("2020-10-08T09:39:27Z") 
}

1 Answer 1

1

When you use an operator check if it can take as argument an expression, like here a field reference.

{ $push: { <field1>: <value1>, ... } }

MongoDB can do much more,with mongodb >= 4.2 you can do updates using the aggregation pipeline.

I give you the command,the "q" is the query,the "u" is the update pipeline, you can use it with any driver that supports mongodb >= 4.2

> use testdb
switched to db testdb
> db.testcoll.drop()
true
> db.testcoll.insert(
... { 
...     "_id" : "5f7dabb9c02c0000d2003ec2", 
...     "USUARIO" : "admin", 
...     "START" :ISODate("2020-10-07T11:51:21Z"), 
...     "INTERMISSIONS" : [ ], 
...     "END" : ISODate("2020-10-08T09:39:27Z")
... }
... )
WriteResult({ "nInserted" : 1 })
> db.runCommand(
... {
...   "update": "testcoll",
...   "updates": [
...     {
...       "q": {},
...       "u": [
...         {
...           "$addFields": {
...             "INTERMISSIONS": {
...               "$concatArrays": [
...                 "$INTERMISSIONS",
...                 [
...                   "$END"  //or use {"start" : "$END"},anything you want to add
...                 ]
...               ]
...             }
...           }
...         }
...       ],
...       "multi": false
...     }
...   ]
... }
... )
{ "n" : 1, "nModified" : 1, "ok" : 1 }
> db.testcoll.find({}).pretty();
{
    "_id" : "5f7dabb9c02c0000d2003ec2",
    "USUARIO" : "admin",
    "START" : ISODate("2020-10-07T11:51:21Z"),
    "INTERMISSIONS" : [
        ISODate("2020-10-08T09:39:27Z")
    ],
    "END" : ISODate("2020-10-08T09:39:27Z")
}

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

1 Comment

After tinkering with your query for a bit longer and trying to make it a "normal" query for the sake of standardization with the rest of my code, i assume there's no way to do this with an update query (other than using $out, which i guess it not specially efficient). If i'm mistaken please tell me so i don't have to look up everything again in a few months :)

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.