2

Am planning on using Mongo ObjectIDs to compare Timestamps i.e. :

$fourteenDaysAgo = time() - (14 * 86400);

$lookFor = array(
    '_id' => $user
);
$updateFields = array(
    '$pull' => array(
        'Rewards' => array(
            '_id' => array(
                '$lt' => new MongoId(dechex($fourteenDaysAgo).'0000000000000000')
            )
        ),
    ),
);
$returnFields = array(
    '_id' => 1,
);

$userData = $db->users->findAndModify($lookFor, $updateFields, $returnFields);

The thing that irks me is this specifically

new MongoId(dechex($fourteenDaysAgo).'0000000000000000')

This has an uneasy, "hackish", feel about it compared to other libraries C# or Py where there's simply something like:

ObjectId.from_datetime( fourteen_days_ago )

I've been looking at the docs, but can't seem to find the equivalent for PHP... does it not exist? Is there a better way? I.e. Something that won't make me go "wtf was i doing here?" when i eventually revisit this script N months later?

Community
  • 1
  • 1
gyeo
  • 63
  • 6

1 Answers1

0

I definitely agree on that being a bit hackish, but it's not as bad as it seems. To understand though, let's take a look at what an ObjectID is made out of. They're 12 bytes, represented in 24 bytes of hex

  • a 4-byte value representing the seconds since the Unix epoch,
  • a 3-byte machine identifier,
  • a 2-byte process id, and
  • a 3-byte counter, starting with a random value.

By tacking on 12 zeroes, it's blanking out the rest of the data that makes up a normal hash. Taking into consideration that the machine identifier, process ID, and random counter are there to prevent the same ID being inserted into the DB twice, the act of faking that data for a comparison isn't so bad. All the query is doing is using the first 4 bytes anyways.

This method of just dechexing timestamps also has the potential of returning less than 8 bytes of hex, which would cause Mongo to discard the hash and create a new one based on right now. (Or, more recently, fatal error) I'd recommend:

$timestamp = str_pad(dechex($timestamp), 8, '0', STR_PAD_LEFT);

Looking deeper, we can take a look at the actual Mongo PHP extension, and we can emulate that creation process. If you needed an ID to be predated that's going to end up in the database, I'd just create a new ID and swap out the first 8 hex characters:

$id = new MongoId($timestamp.substr(new MongoID(), 8));
Kavi Siegel
  • 2,964
  • 2
  • 24
  • 33