Search code examples
mongodbrmongodb

Use of mongo.code.create to construct array argument to $add


I have MongoDB documents like the following:

{"_id":{"$oid":"56d810f5c91e6779a38386b8"},
 "timestamp": {"$numberLong":"1457000674750"}}

I am constructing an aggregration pipeline which should contain the following $project segment:

{"$project": 
    {"date": {"$add": ["new Date(3600000)", "$timestamp"]}}
}   

This works in MongoDB shell, but I can't get it to work with rmongodb. For instance, the following gives error 10 (BSON invalid) when included in my pipeline:

mongo.bson.from.list(list(
"$project"= list("date"=list("$add"=list( mongo.code.create("new Date(3600000)"), "$timestamp")))
))

I'm pretty sure the problem relates to the code (new Date(3600000)) and/or its inclusion in an array which is in turn an argument to $add. I suppose I can construct the BSON buffer the "old way", but what I'm looking for is how to do this with mongo.bson.from.list and/or mongo.bson.from.JSON.


Solution

  • As stated, it's not "JavaScript Code" that needs to be used to represent a BSON Date for injection, but rather whatever the native format is for a Date in the language environment.

    So in r, you can use the following sort of constructor to get the Date as of epoch:

    as.POSIXct("1970-01-01",tz="GMT")
    

    So in the example of doing a BSON Date conversion on a numeric value and extracting the $year from that:

    pipeline <- list(
      mongo.bson.from.list(list(
        '$project' = list(
          'test' =  list( '$year' = 
            list( '$add' = list (
              '$timestamp',
              as.POSIXct("1970-01-01",tz="GMT"),
              3600000
            ))
          )
        )
      ))
    )
    

    That said, there is nothing stopping you from just applying the basic math directly to the numeric value, just as an operator example to the serialized notation:

    { "$project": {
        "test": {
            "$add": [
                { "$divide": [
                    { "$subtract": [
                        { "$add": [ "$timestamp",3600000 ] },
                        { "$mod": [ 
                            { "$add": [ "$timestamp", 3600000 ] }, 
                            1000 * 60 * 60 * 24 * 365
                        ]}
                    ]},
                    1000 * 60 * 60 * 24 * 365
                ]},
                1970
            ]
        }
    }}
    

    Also works out the current "year", and the same sort of operations can be applied to any part of a date, be it the current "year" of "dayOfYear" or anything.

    Also note that $project usage is not really recommended if you intend to $group as you would be better off just using your "conversions" directly into the grouping _id rather than in a separate pipeline stage, for performance reasons in avoiding another pipeline pass.

    The only time it would really be necessary to $add to a Date would be in the final output of a converted "millisecond from epoch" value in "output" where you wanted a BSON Date rather than the numeric value.