我必须从MySQL导入大量数据到MongoDB,我想使用来自ObjectID的时间戳,而不是将其存储在单独的键/值中(因为它在现有数据中)。为了做到这一点,我需要为现有数据创建一个带有过去日期的ObjectID。我还需要使用PHP驱动程序来做到这一点。我读到在Python, Java和Node.JS中可能有一种方法可以做到这一点,所以我想也许在PHP中有一个等效的方法。
如果这是可能的-它是安全的吗?意思是,我会遇到重复或无效的objectid问题吗?谢谢。
在node . js:var timestamp = Math.floor(new Date().getTime()/1000);
var objectId = new ObjectID(timestamp);
下面是来自MongoDB使用时间戳排序
在Python中:
gen_time = datetime.datetime(2010, 1, 1)
dummy_id = ObjectId.from_datetime(gen_time)
Java: Date d = new Date(some timestamp in ms);
ObjectId id = new ObjectId(d)
现在,PHP驱动程序没有内置的功能,另一个答案提到的__set_state()只是为了能够会话反序列化ID,不允许您通过特定的组件创建它。
您必须执行以下操作来自动创建ID:
<?php
function createId( $yourTimestamp )
{
static $inc = 0;
$ts = pack( 'N', $yourTimestamp );
$m = substr( md5( gethostname()), 0, 3 );
$pid = pack( 'n', posix_getpid() );
$trail = substr( pack( 'N', $inc++ ), 1, 3);
$bin = sprintf("%s%s%s%s", $ts, $m, $pid, $trail);
$id = '';
for ($i = 0; $i < 12; $i++ )
{
$id .= sprintf("%02X", ord($bin[$i]));
}
return new MongoID($id);
}
var_dump( createId( time() ) );
?>
如果您使用MongoId只是为了比较,例如,选择一个日期范围内的所有记录,则不需要一个完全有效的id。所以你可以简单地输入:
$id = new MongoId(dechex($timestamp) . str_repeat("0", 16));
请确保永远不要插入这个id,只在$gte/$gt/$lt/$lte查询时使用它。
编辑
我的错,上面的代码片段可以处理1979年之前的日期,因为dechex($timestamp)
并不总是返回8个字符,所以更好的代码片段应该是:
$id = new MongoId(sprintf("%08x%016x", $timestamp, 0));
这可能会产生问题,因为使objectid唯一的因素之一是时间部分,但是它应该在相同的时间内增加多个插入的最后一个字节(或左右)。
看起来有一些动作是允许用一些参数创建一个ObjectId事实上它几乎在这里讨论它:http://php.net/manual/en/mongoid.set-state.php
理论上,是一个用于创建新id的属性数组。但是,由于MongoId实例没有属性,所以不使用这个。
但是,我相信,如果不编写自己的ObjectId
生成器,就没有办法实现在其他语言中可以实现的功能。
我发现这里标记为正确的解决方案不适合我。所以,我给出了可行的解决方案。无论如何,在运行代码之前,确保按照以下两个官方教程安装了mongodb和mongodb php驱动程序:
(1) https://www.mongodb.com/docs/manual/administration/install-community/
(2) https://www.mongodb.com/docs/drivers/php/
然后打开你的项目目录,在终端/cmd中运行命令:
composer require mongodb/mongodb
(如上文第(2)条所述)。上面的命令会自动配置你所有的依赖项。
以上操作完成后,运行如下命令创建一个基于时间戳的ObjectId的代码片段:
<?php
require_once __DIR__ . '/vendor/autoload.php';
// connect to mongodb
$con = new MongoDBClient("mongodb://localhost:27017");
function createObjectIdFromTimestamp($timeStamp) {
$next_first_4bytes = (string) dechex(rand(1, 65535));
$next_second_4bytes = (string) dechex(rand(1, 65535));
$next_third_4bytes = (string) dechex(rand(1, 65535));
$next_fourth_4bytes = (string) dechex(rand(1, 65535));
$timeStamp = $timeStamp . $next_first_4bytes . $next_second_4bytes . $next_third_4bytes . $next_fourth_4bytes;
$newId = new MongoDBBSONObjectId($timeStamp);
return $newId;
}
// creating a timestamp for 15th March 2013, 03:45:23 am:
$date = date_create_from_format("d-M-Y h:i:s a","15-Mar-2013 03:45:23 am");
// just change the above statement to a date and time you want to create your timestamp for.
/*
To create a date in the format PHP can understand,
the above statement was written. '$date' is a variable
that has stored the date in the format that PHP understands.
In the function: date_create_from_format(),
d = date of the month (in 2 digits), e.g: 15 (in the above statement),
M = name of month (in 3 letters), e.g: Mar (in the above statement),
Y = year (in 4 digits), e.g: 2013 (in the above statement),
h = hour (in 12 hrs format) (in 2 digits), e.g: 03 (in the above statement),
i = minutes (in 2 digits), e.g: 45 (in the above statement),
s = seconds (in 2 digits), e.g. 23 (in the above statement),
a = am or pm, e.g. am (in the above statement)
*/
$timestmp = substr((string) dechex($date -> getTimestamp()), 0, 8);
$id = createObjectIdFromTimestamp($timestmp);
// echo "$id = " . $id . "<br>";
?>
如果您想在当前日期创建对象id,那么只需将上面的整个代码片段替换为如下所示的php语句:
<?php
require_once __DIR__ . '/vendor/autoload.php';
// connect to mongodb
$con = new MongoDBClient("mongodb://localhost:27017");
$id = new MongoDBBSONObjectId();
?>
我已经在Ubuntu中测试了我的解决方案