skip to Main Content

I’m using MongoDB version 3.4.17, accessed via PHP (MongoDB PHP API version 1.4). When the server writes a JSON document to the database, it first adds a timestamp field like so:

$record['date_modified'] = new MongoDBBSONUTCDateTime();

When reloading this record, which is serialized into a JSON, used by JavaScript, then passed back to the server to be saved with collection->replaceOne(), I get this error:

invalid argument for replace: keys cannot begin with "$": "$date""

The JavaScript console shows the date as an object with multiple levels of child objects:

date_modified:
   $date:
       $numberLong: "1572318771000"

Questions:

  1. What should I be doing differently so I can save the JSON back to the database without it throwing the error it does for ‘keys cannot begin with "$"?

  2. It would be handy for JavaScript to have the date in a more useful format. Like maybe a string that the JavaScript Date() method could take in its constructor. Should I be using one of these methods on the server side to convert it?

2

Answers


  1. Chosen as BEST ANSWER

    I ended up coming up with this code that I tested and it solves the problem. It does feel like a bit of a 'hack' and I'm not sure why it's required, but it does work. It looks for fields of the structure:

    anyField: {
       $date: {
           $numberLong: "1572318771000"
       }
    }
    

    and converts it into a UTCDateTime.

    public static function fixMongoDBTimestampFields(&$record)
    {
        foreach ($record as $fieldName => &$value)
        {
            if (is_array($value) || ($value instanceof Traversable))
            {
                if ( array_key_exists( '$date', $value) && is_array($value['$date']) && array_key_exists( '$numberLong', $value['$date']) )
                {
                    $millisecs = $value['$date']['$numberLong'];
                    $value = new MongoDBBSONUTCDateTime($millisecs);
                }
    
                self::fixMongoDBTimestampFields($value);
            }
        }
        unset($value);
    }
    

  2. How do you insert the data and how do you retrieve it?

    I use this, and it works fine:

    use MongoDBBSONUTCDateTime;
    $doc = [
        "input" => $input,
        "host" => gethostname(),
        "timestamp" => new UTCDateTime(NULL),
    ];
    $ret = $logging->insertOne($doc); 
    

    In order to convert a Mongo BSON date back to PHP Date, use MongoDBBSONUTCDateTime::toDateTime

    If you need to work with JSON strings, then these commands would be useful:

    use function MongoDBBSONtoRelaxedExtendedJSON;
    use function MongoDBBSONfromPHP;
    use function MongoDBBSONtoPHP;
    use function MongoDBBSONfromJSON;
    

    Here is an example how they could be used:

    $match = []; 
    $match["dp"] = 123; 
    
    $find_time = []; 
    $find_time["t0"] = ['$lte' => new UTCDateTime($value)];
    
    $pipeline = []; 
    array_push($pipeline, array('$match' => $find_time) ); 
    
    $json = []; 
    array_push($json, '{ "$unset": ["h", "sp", "tdp", "tdi"] }');
    array_push($json, toRelaxedExtendedJSON(fromPHP(array('$match' => $match)))); 
    foreach ($json as $stage) {
        array_push($pipeline, toPHP(fromJSON($stage)));
    }
    
    foreach ($collection->aggregate($pipeline, array('allowDiskUse' => true)) as $row) {
        array_push($ret, self::MongoToArray($row));
    } 
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search