7

I want to insert data in Mongo database using PHP script, in year wise documents so that it may look like this (All years in one document);

cars{
        2017{
            car=Motorolla
            color = blue
        }
        2016{
            car=Toyota
            color = green
        }
        2015{
            car=Corolla
            color = black
        }
    }

I wanted to add the document but it prompts

Document can't have $ prefixed field names: $years[0]

Is it possible to make such schema in Mongo using PHP?

Code

<?php
    try {        
        $car = 'Motorolla';
        $color = 'blue';

        //$car = 'Toyota';
        //$color = 'green';

        //$car = 'Corolla';
        //$color = 'black';

        $years = array(2017, 2016, 2015);       
        $manager = new MongoDB\Driver\Manager("mongodb://localhost:27017");
        $bulkWriteManager = new MongoDB\Driver\BulkWrite;
        $document = ['_id' => new MongoDB\BSON\ObjectID, '$years[0]' => $car, '$years[1]' => $color];   // Making a query type

        try {
            $bulkWriteManager->insert($document);   // Inserting Document
            echo 1;           
        } catch(MongoCursorException $e) {
            /* handle the exception */
            echo 0;
        }

        $manager->executeBulkWrite('dbName.carsCol', $bulkWriteManager);  // Going to DB and Collection

    } catch (MongoDB\Driver\Exception\Exception $e) {
        $filename = basename(__FILE__);
        echo "The $filename script has experienced an error.\n"; 
        echo "It failed with the following exception:\n";       
        echo "Exception:", $e->getMessage(), "\n";


    }

?>

I do not want to add whole car object at once. I want to add Year object every time. Any help will be appreciable. OR Any relative answer so that I may get the data from Mongo Database according to the year?

Edit1

For first time creation. - Credits goes to @Veeram

<?php
    try {        
        $car = 'Malibu';
        $color = 'red';
        $years = array(2017);       

        $manager = new MongoDB\Driver\Manager("mongodb://localhost:27017");
        $bulkWriteManager = new MongoDB\Driver\BulkWrite;
        //{"car":"chevy", "color":"black", year: 2017}
        $insert = ['car' => $car, 'color' => $color, 'year' => $years[0]];
        try {
            $bulkWriteManager -> insert($insert); // Inserting Document
            echo 1;
        } catch (MongoCursorException $e) {
            echo 0;
        }
        $manager->executeBulkWrite('dbName.mycol', $bulkWriteManager);  // Going to DB and Collection           
    } catch (MongoDB\Driver\Exception\Exception $e) {
        $filename = basename(__FILE__);
        echo "The $filename script has experienced an error.\n"; 
        echo "It failed with the following exception:\n";       
        echo "Exception:", $e->getMessage(), "\n";
        echo "In file:", $e->getFile(), "\n";
        echo "On line:", $e->getLine(), "\n";    
    }
?>

For the updation- Credits goes to @Veeram

<?php
    try {        
        $car = 'ChangedCar';
        $color = 'changedColor';
        $years = array(2017);

        $manager = new MongoDB\Driver\Manager("mongodb://localhost:27017");
        $bulkWriteManager = new MongoDB\Driver\BulkWrite;

        $query = ['cars.year' => $years[0]]; 

        //{ $push: { "cars.$.data": { "car":"chevy", "color":"black"} }}
        $update = ['$push'=> ['cars.$.data'=>['car' => $car, 'color' => $color]]];
        try {
            $bulkWriteManager->update($query, $update);   // Inserting Document        
        } catch(MongoCursorException $e) {

        }
        $manager->executeBulkWrite('dbName.mycol', $bulkWriteManager);  // Going to DB and Collection
    } catch (MongoDB\Driver\Exception\Exception $e) {
        $filename = basename(__FILE__);
        echo "The $filename script has experienced an error.\n"; 
        echo "It failed with the following exception:\n";       
        echo "Exception:", $e->getMessage(), "\n";
    }
?>

The problem in this code is that it successfully insert the data for the first time but when i update the data it does not update it.

Example: There is a document named as cars . Insert the data with object of year in one document. Let's say the Object is 2017, it contains color and car Model. As showing below; (Multiple objects with years. Year is unique in whole document.)

cars{
        2017{
            car=Motorolla
            color = blue
        }
        2016{
            car=Toyota
            color = green
        }
        2015{
            car=Corolla
            color = black
        }
    } 

If I want to update just make an object of 2017 like 2017{car=Updated-Motorolla color =Updated-blue} and insert in the document. It should update only the year 2017 object in side the document.

 cars{
            2017{
                car=Updated-Motorolla
                color =Updated-blue
            }
            2016{
                car=Toyota
                color = green
            }
            2015{
                car=Corolla
                color = black
            }
        } 
8
  • Show us the code you currently have. Commented Feb 17, 2017 at 13:32
  • Code is given above. Commented Feb 18, 2017 at 4:07
  • What structure of document you want to have? what data can be used to find document that is going to be updated (for example maybe document must be connected to some user)? Commented Feb 20, 2017 at 15:16
  • @VadimKokin I want to add the data year wise and same for the access. (on the basis of year). Commented Feb 20, 2017 at 15:19
  • So you will have many documents that have information about 2017, 2016, etc. How do you want to filer them? Or you will have only one document and change information in it? Commented Feb 20, 2017 at 15:25

2 Answers 2

4

You can try something like this. Its not possible to perform all the Mongo db operations just based off key as a value.

The first solution is written to stay close to OP's design.

Assuming you can add a key to the year.

{
  "cars": [{
      "year": "2017",
      "data": [{
          "car": "Motorolla",
          "color": "blue"
      }]
  }, {
      "year": "2016",
      "data": [{
          "car": "Toyota",
          "color": "green"
      }]
  }]
}

Makes it easy to reference the year by its value.

For example to add a new value into the data array for year 2017. You can try the below code.

Uses update positional $ operator.

query part to reference the array where 2017 record is stored.

update part using push to add the new car record to the existing data array for 2017 row.

<?php
    try {        
        $car = 'Malibu';
        $color = 'blue';
        $years = [2017];

        $manager = new MongoDB\Driver\Manager("mongodb://localhost:27017");
        $bulkWriteManager = new MongoDB\Driver\BulkWrite;

        //{"cars.year":2017}
        $query = ['cars.year' => $years[0]]; 

        //{ $push: { "cars.$.data": { "car":"chevy", "color":"black"} }}
        $update = ['$push'=> ['cars.$.data'=>['car' => $car, 'color' => $color]]];

        try {
            $bulkWriteManager->update($query, $update);  // Update Document
            echo 1;           
        } catch(MongoCursorException $e) {
            /* handle the exception */
            echo 0;
        }

        $manager->executeBulkWrite('dbName.carsCol', $bulkWriteManager);  // Going to DB and Collection

    } catch (MongoDB\Driver\Exception\Exception $e) {
        $filename = basename(__FILE__);
        echo "The $filename script has experienced an error.\n"; 
        echo "It failed with the following exception:\n";       
        echo "Exception:", $e->getMessage(), "\n";
    }

?>

For accessing data by year you can run below query.

Use query positional $operator to find the array index using the query part and reference that value in projection part.

db.collection.find({"cars.year":2017}, {"cars.$.data":1});

Alternative Solution :

This will take care of everything as just inserts

You are better off saving each car entry in its own document.

{ "year" : 2017, "car" : "Motorolla", "color" : "blue" }
{ "year" : 2016, "car" : "Toyota", "color" : "green" }
{ "year" : 2015, "car" : "Corolla", "color" : "black" }

For each entry you can use:

db.collection.insert({"year":2017,  "car":"Motorolla", "color":"blue"});

PHP Code:

 //{"car":"chevy", "color":"black", year: 2017}
 $insert = ['car' => $car, 'color' => $color, 'year' => $years[0]];

 try {
    $bulkWriteManager - > insert($insert); // Inserting Document
    echo 1;
 } catch (MongoCursorException $e) {
    /* handle the exception */
    echo 0;
 }

For access data by year you can use

db.collection.find({"year":2017});

Updated PHP code:

<?php 
try { 
  $cars = ['Motorolla','Toyota', 'Corolla'] ; 
  $colors = ['blue', 'green', 'black']; 

  $years = [2017, 2016, 2015]; 
  $manager = new MongoDB\Driver\Manager("mongodb://localhost:27017"); 
  $bulkWriteManager = new MongoDB\Driver\BulkWrite; 

  $query1 =["year" => $years[0]]; 
  $query2 =["year" => $years[1]]; 
  $query3 =["year" => $years[2]]; 

  $update1 = ['$set' => ['car' => $cars[0], 'color' => $colors[0]]]; 
  $update2 = ['$set' => ['car' => $cars[1], 'color' => $colors[1]]]; 
  $update3 = ['$set' => ['car' => $cars[2], 'color' => $colors[2]]]; 

  try { 
    $bulkWriteManager->update($query1, $update1, ["upsert" => true]); 
    $bulkWriteManager->update($query2, $update2, ["upsert" => true]); 
    $bulkWriteManager->update($query3, $update3, ["upsert" => true]); 
     echo 1; 
  } catch(MongoCursorException $e) { 
  /* handle the exception */ 
  echo 0; 
  } 

  $manager->executeBulkWrite('dbName.carsCol', $bulkWriteManager); // Going to DB and Collection 

  } catch (MongoDB\Driver\Exception\Exception $e) { 
    $filename = basename(__FILE__); 
    echo "The $filename script has experienced an error.\n"; 
    echo "It failed with the following exception:\n"; 
    echo "Exception:", $e->getMessage(), "\n"; 
  } 
?>

You can perform complex queries using aggregation pipeline and you can add index to make your response quicker.

Observations:

First Solution : Harder to update/insert data, but keeps everything together so easier to read data.

Second Solution : Cleaner and simpler to do CRUD operations on documents and use aggregation pipeline to preform complex queries.

Sign up to request clarification or add additional context in comments.

12 Comments

What if i want to retrieve the data on basis of Year?
Kindly elaborate this line {"cars.$.data":1});
Will your code run if the dbName not exist ? Means there is no data exist in database.
Updated answer with more explanation. Not sure what you mean by dbName dont exist. Are you talking what happens first time when you insert data ? Try it out.
I tried it. Not inserting any data for the first time.
|
0
+50

Try to change

$document = ['_id' => new MongoDB\BSON\ObjectID, '$years[0]' => $car, '$years[1]' => $color];

to something like:

$document = ['_id' => new \MongoDB\BSON\ObjectID, $years[0] => ['car' => $car, 'color' => $color]];

it gives such result in mongo:

{ "_id" : ObjectId("58a936ecfc11985f525a4582"), "2017" : { "car" : "Motorolla", "color" : "blue" }

If data about all cars must be in one document, you need to combine data fitst:

$cars = [
    '2017' => [
        'car' => 'Motorolla',
        'color' => 'blue'
    ],
    '2016' => [
        'car' => 'Toyota',
        'color' => 'green'
    ],
    '2015' => [
        'car' => 'Corolla',
        'color' => 'black'
    ]
];

and than

$document = ['_id' => new \MongoDB\BSON\ObjectID, 'cars' => $cars]; 

It gives mongo document like:

{ "_id" : ObjectId("58aabc0cfc11980f57611832"), "cars" : { "2017" : { "car" : "Motorolla", "color" : "blue" }, "2016" : { "car" : "Toyota", "color" : "green" }, "2015" : { "car" : "Corolla", "color" : "black" } } }

5 Comments

On using your suggestion, it adds every year wise document in a new document when I add another year (When I call script again). I want to add all years in only one document. Is it possible?
I do not need to add the whole document at once. The data comes after some time. How to combine the newly data into the last document?
You need to use update instead of insert: $bulkWriteManager->update(['_id' => new \MongoDB\BSON\ObjectID('58aabc0cfc11980f57611832')], ['cars' => $cars]);
But I think it is not a way to do that. How can I get the Object ID of added document? I do want to send the car data for update. I want to sent the year data .
If you want to update same document you have to find it in your DB, so you will have Object ID. And than you can update information about year/car

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.