使用PHP驱动程序从过去的日期创建MongoDB ObjectID


Create MongoDB ObjectID from date in the past using PHP driver

我必须从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 MongoDB'Client("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 MongoDB'BSON'ObjectId($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 MongoDB'Client("mongodb://localhost:27017"); 
$id = new MongoDB'BSON'ObjectId();
?>

我已经在Ubuntu中测试了我的解决方案