Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reference an existing ObjectId during new document insertion using PHP/Phalcon/MongoDB

I have used the below code to insert Primary category id reference to Secondary category document using robomongo client

    var parentDoc = db.getCollection('category').findOne({"slug":"Primary"});
    db.category.insert(
    {
        "name" : "Secondary",
        "slug" : "secondary",
        "taxonomy" : true,

        "ancestors" : [
        {
            "_id" : parentDoc._id,
            "name" : parentDoc.name
        }
        ]
    })

i have tried the below in PHP style

$query = '
    {
        "slug" : "fashion"
    }';
    $primaryCategory = Category::findFirst(array(json_decode($query,true))); //phalcon code
    $primary = array();
    $primary['_id'] = $primaryCategory->_id;
    $primary['name'] = $primaryCategory->name;

    $document = array(
            "name" => "Secondary2",
            "slug" => "secondary",
            "taxonomy" => true,
            "ancestors" => array($primary)
    );
    $category = $app->mongo->selectCollection('category');//phalcon style of fetching collection handle
    $category->insert($document);

    });

And tried in Phalcon style

$query = '
    {
        "slug" : "fashion"
    }';
    $primaryCategory = Category::findFirst(array(json_decode($query,true)));
    $cat = new Category(); // new secondary category
    $cat->name = 'Secondary';
    $cat->slug = 'secondary';
    $cat->taxonomy = true;
    $cat->ancestors = array();
    $primary = array();
    $primary['_id'] = $primaryCategory->_id;
    $primary['name'] = $primaryCategory->name;
    array_push ( $cat->ancestors, $primary );
    $cat->save();

In the above code there are 2 round trips between server and mongo

  1. The first one for getting parentDoc
  2. The second one for inserting secondaryDoc with parentDoc reference Id

Is it possible to execute them in 1 roundtrip where I could reference the parentDocId while secondaryDoc insertion

like image 759
Faiz Mohamed Haneef Avatar asked Sep 02 '26 15:09

Faiz Mohamed Haneef


1 Answers

You can leverage your insert operations by using the Bulk API which is available from MongoDB 2.6 or higher. The current PHP driver should support these methods, where in particular you need the MongoWriteBatch class which extends the MongoInsertBatch class for insert operations. In essence, the operation can be implemented as following:

<?php
    $mc = new MongoClient("localhost");
    $collection = $mc->selectCollection("test", "category");

    $batch = new MongoInsertBatch($collection);
    $counter = 0;
    $query = array("slug" => "Primary");

    foreach ($collection->find($query) as $doc ) {

        $primary = array();
        $primary['_id'] = $doc->_id;
        $primary['name'] = $doc->name;

        $doc = array(
            "name" => "Secondary2",
            "slug" => "secondary",
            "taxonomy" => true,
            "ancestors" => array($primary)
        );
        $batch->add($doc);
        $counter++;

        if ( $counter % 1000 === 0 ) {
            $ret = $batch->execute(array("w" => 1));
            $counter++;
            $batch = new MongoInsertBatch($collection);        
        }
    }

    if ( $counter > 0 ) {
        $ret = $batch->execute(array("w" => 1));
    }
?>

In the above, each find() query and insert operation is added to a batch via the .add() method to be sent to the server, in the order provided, for serial execution. So rather than waiting for the write response from the server for each insert, the operations are sent and responded to in batches hence there is less overhead in roundtrips.

like image 124
chridam Avatar answered Sep 05 '26 06:09

chridam