6

我必须将大量数据从 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)
4

3 回答 3

11

目前,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() ) );
?>
于 2013-01-17T13:23:21.443 回答
7

如果您仅使用 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));
于 2013-03-12T13:18:11.310 回答
0

这可能会产生问题,因为使 objectid 唯一的因素之一是时间部分,但是它应该在同一时间增加多个插入的最后一个字节(左右)。

看起来有一些允许使用一些参数创建 ObjectId 的运动,事实上它几乎在这里谈论它:http: //php.net/manual/en/mongoid.set-state.php

理论上,用于创建新 id 的属性数组。但是,由于 MongoId 实例没有属性,因此不使用它。

但是没有办法,atm,我相信无需编写自己的ObjectId生成器就可以实现其他语言可以做的事情。

于 2013-01-17T10:08:34.123 回答