alfonsodev
alfonsodev

Reputation: 2754

php Mongodb "$oid is not valid for storage" error when inserting from JSON export

I have a file with following data exported with mongodb mongoexport command:

mongoexport --db mydb --collection Users --out Users.json --jsonArray --journal

Users.json contains:

[
    {
      "_id" : { "$oid" : "53c3e81ebb593fe827040ef7" },
      "email" : "[email protected]",
      "password" : "$2y$10$OYN9qOPa8EAU202Nsee7s.jDyT8ntHq2mBkM4wWAMxDYvARRyKmr2"
    }
]

I want to import data without mongoimport command, just using php client, so I do

$fixtures = file_get_contents($fixturesPath . '/' . $fixtureFile);
$rows = json_decode($fixtures, true);
foreach ($rows as $row) {
  $this->db->Users->insert($row);
}

var_dump of $row just before the insert is correct:

(
  [_id] => Array
    (
        [$oid] => 53c3e81ebb593fe827040ef7
    )

  [email] => [email protected]
  [password] => $2y$10$OYN9qOPa8EAU202Nsee7s.jDyT8ntHq2mBkM4wWAMxDYvARRyKmr2
)

I get the following error:

[MongoWriteConcernException]
localhost:27017: $oid is not valid for storage.

The question is, how can I do to import this data from php ?
Obviously by removing _id line it works, but I think I need this id so I can tests always with the user ids .

Upvotes: 2

Views: 6322

Answers (2)

alfonsodev
alfonsodev

Reputation: 2754

Neil Lunn, and Sammaye, are correct. They pointed me to the solution, and marked Neils as correct.

But also wanted to leave here my own solution as you can also have subdocuments I ended writing this recursive function to replace all $oid

private function replaceMongoIds(&$document, $name = false)
{
    foreach (array_keys($document) as $key) {
        if ($key == "_id" && isset($document[$key]['$oid'])) {
            $document[$key] = new \MongoId($document[$key]['$oid']);
        } else if ($name && is_array($document[$key]) && isset($document[$key]['$oid'])) {
            $document[$key] = new \MongoId($document[$key]['$oid']);
        } else if (is_array($document[$key]) ) {
           $this->replaceMongoIds($document[$key], $key);
        }
    }
}

so now my code looks like

$fixtures = file_get_contents($fixturesPath . '/' . $fixtureFile);
$rows = json_decode($fixtures, true);
foreach ($rows as $row) {
  $this->replaceMongoIds($row);
  $this->db->Users->insert($row);
}  

Upvotes: 3

Neil Lunn
Neil Lunn

Reputation: 151122

By default, uses the "extended JSON syntax" standard for MongoDB. This is because JSON is not "typed" where BSON is and certain data is expected to be "typed", in this case the ObjectId.

So if you are dealing with JSON in the "extended syntax" form then you need to convert it:

foreach ( $rows as $row ) {
    foreach ( array_keys($row) as $key) {
        if ( $key == "_id" ) {
            $row[$key] = new \MongoId( $row[$key]['$oid'] );
        }
    }
    $this->db->Users->insert( $row );
}

Or something similar, as looping here would be more practical if you were "detecting" this and other types. But basically you need to "convert" any of these special types from that extended representation in JSON.

Upvotes: 5

Related Questions