[英]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:问题:
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 保存回数据库,而不会抛出它为“键不能以“$”开头的错误?
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.