简体   繁体   English

如何替换具有 BSON UTCDateTime 的 MongoDB 记录?

[英]How to replace MongoDB records that have a BSON UTCDateTime?

I'm using MongoDB version 3.4.17, accessed via PHP (MongoDB PHP API version 1.4).我正在使用 MongoDB 版本 3.4.17,通过 PHP 访问(MongoDB PHP ZDB974238714CA8DE634A 版本 CE)。 When the server writes a JSON document to the database, it first adds a timestamp field like so:当服务器将 JSON 文档写入数据库时,它首先添加一个时间戳字段,如下所示:

$record['date_modified'] = new MongoDB\BSON\UTCDateTime();

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:当重新加载此记录时,它被序列化为 JavaScript 使用的 JSON,然后传递回服务器以使用 collection->replaceOne() 保存,我收到此错误:

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

The JavaScript console shows the date as an object with multiple levels of child objects: JavaScript 控制台将日期显示为具有多级子对象的 object:

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 "$"?我应该做些什么不同的事情,这样我就可以将 JSON 保存回数据库,而不会抛出它为“键不能以“$”开头的错误?

  2. It would be handy for JavaScript to have the date in a more useful format. JavaScript 将日期设置为更有用的格式会很方便。 Like maybe a string that the JavaScript Date() method could take in its constructor.就像 JavaScript Date() 方法可以在其构造函数中接收的字符串一样。 Should I be using one of these methods on the server side to convert it?我应该在服务器端使用其中一种方法来转换它吗?

How do you insert the data and how do you retrieve it?您如何插入数据以及如何检索数据?

I use this, and it works fine:我用这个,它工作正常:

use MongoDB\BSON\UTCDateTime;
$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 MongoDB\BSON\UTCDateTime::toDateTime要将 Mongo BSON 日期转换回 PHP 日期,请使用MongoDB\BSON\UTCDateTime::toDateTime

If you need to work with JSON strings, then these commands would be useful:如果您需要使用 JSON 字符串,那么这些命令会很有用:

use function MongoDB\BSON\toRelaxedExtendedJSON;
use function MongoDB\BSON\fromPHP;
use function MongoDB\BSON\toPHP;
use function MongoDB\BSON\fromJSON;

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));
} 

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.并将其转换为 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 MongoDB\BSON\UTCDateTime($millisecs);
            }

            self::fixMongoDBTimestampFields($value);
        }
    }
    unset($value);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM