I have two problem : How can I get affected rows by php mongodb driver ,and how about the last insert id ? thanks .
You can get number of results right from the cursor using count function:
$collection->find()->count();
You can even get number of all records in collection using:
$collection->count();
Using insert method, _id is added to input array automatically.
$a = array('x' => 1);
$collection->insert($a,array('safe'=>true));
var_dump($a);
array(2) {
["x"]=>
int(1)
["_id"]=>
object(MongoId)#4 (0) {
}
}
I don't believe that there is any type of affected_rows() method at your disposal with mongodb. As for the last insert _id You can generate them in your application code and include them in your insert, so there's really no need for any mysql like insert_id() method.
$id = new MongoId();
$collection->insert(array('
'_id' => $id,
'username' => 'username',
'email' => 'johndoe#gmail.com'
'));
Now you can use the object stored in $id however you wish.
Maybe MongoDB::lastError is what you are looking for:
(http://php.net/manual/en/mongodb.lasterror.php)
It calls the getLastError command:
(http://www.mongodb.org/display/DOCS/getLastError+Command)
which returns, among other things:
n - if an update was done, this is the number of documents updated.
For number of affected rows:
$status = $collection->update( $criteria, array( '$set' => $data ) );
$status['n']; // 'n' is the number of affected rows
If you have the output of your action, you can call relative function:
// $m hold mongo library object
$output = $m->myCollection->updateOne([
'_id' => myMongoCreateID('56ce2e90c9c037dba19c3ce1')], [
'$set' => ['column' => 'value']
]);
// get number of modified records
$count = $output->getModifiedCount();
$output is of of type MongoDB\UpdateResult. Relatively check following files to figure out the best function to find inserted, deleted, matched or whatever result you need:
https://github.com/mongodb/mongo-php-library/blob/master/src/InsertManyResult.php
https://github.com/mongodb/mongo-php-library/blob/master/src/DeleteResult.php
https://github.com/mongodb/mongo-php-library/blob/master/src/InsertOneResult.php
https://github.com/mongodb/mongo-php-library/blob/master/src/UpdateResult.php
Related
I'm trying to generate a statement sheet. For that, I try to insert data into Mysql using foreach. It works great. But I try to escape the insert query if any duplicate row found in database. I do not want to escape the whole process, but it should escape if a duplicate row found and continue with the next insert query.
$gps = $this->Webmastermodel->acquireStatementDetail();
foreach($gps as $statement){
$insertdata = array(
'product_invoice_id' => $statement['InvoiceNo'],
'PUC' => $statement['productPUC'],
'productQTY' => $statement['productQty'],
'product_sub_total' => $statement['productSubTotal'],
'commissionGain_on_SubTotal' => $statement['commisionChargedOnProductSubTotal']
);
$this->db->insert('partner_business', $insertdata);
}
I would use insert_batch if i were you:
$insertdata = array();
foreach($gps as $statement)
{
$insertdata[] = array(
'product_invoice_id' => $statement['InvoiceNo'],
'PUC' => $statement['productPUC'],
'productQTY' => $statement['productQty'],
'product_sub_total' => $statement['productSubTotal'],
'commissionGain_on_SubTotal' => $statement['commisionChargedOnProductSubTotal']
);
}
$this->db->insert_batch('partner_business', $insertdata);
But since your question is about skipping if a row already exits, you can modify your query and use replace instead:
$this->db->replace('partner_business', $insertdata);
Keeping in mind that its all about providing the right primary_key in your $data array, if there is and existing id it will update its data else it will insert a new row.
I'm using mongodb_ecto and I want to know how can I do operations like $push or $pull on a deeply nested field? At the moment I write back the whole document which sometimes causes false data to be in the DB due to a race-condition.
Ok, I kind of figured it out. Do not use Ecto for this. In some cases you need the MongoDB positional operator and this can only be done directly via the Mongo-Adapter. Now for some usage examples:
I have a doucment with a list of options. Options have an ID, a label and list of userIDs who voted for this option.
BTW to generate an ObjectID (which is needed for talking directly to the MongoDB-Adapter) use this:
id = "584a5b9419d51d724d146e3f" # string form
value = (for <<hex::16 <- id>>, into: <<>>, do: <<String.to_integer(<<hex::16>>, 16)::8>>)
object_id = %BSON.ObjectId{value: value}
And now for some examples:
# update label of option
Mongo.update_one(Repo.Pool, "polls",
%{"_id" => document_id, "options.id" => option_id}, # query
%{"$set" => %{"data.options.$.label" => new_label}} # update
)
# add new option to poll
Mongo.update_one(Repo.Pool, "polls",
%{"_id" => document_id},
%{"$addToSet" => %{"options" => %{label: label, id: random_new_id, votes: []}}}
)
# add user_id to option
Mongo.update_one(Repo.Pool, "polls",
%{"_id" => document_id, "options.id" => option_id},
%{"$addToSet" => %{"options.$.votes" => user_id}}
)
# remove user_id form option
Mongo.update_one(Repo.Pool, "polls",
%{"_id" => document_id, "options.id" => option_id},
%{"$pull" => %{"data.options.$.votes" => user_id}}
)
Hi i am working on backend of web application & want to find the documents from mongodb database that contain key active_status with value set to both 1 & 2. With mongodb PHP i am confused of how to find with both parameters in single query.
My query was this:
$mongoDb = MongoDbConnector::getCollection("endusers");
$endUserData = $mongoDb->find(array('active_status' => 1, '$and' => array('active_status' => 2)));
I have to fetch the users whose active_status should be 1 & 2. The above query doesnt seems to work. What is the right one for that?
Thanks on advance for quick response.
You have $and the wrong way around. Both arguments need to be included:
$endUserData = $mongoDb->find(array(
'$and' => array(
array( 'active_status' => 1 )
array( 'active_status' => 2 )
)
));
And since that would only make sense when looking for both elements within an array element, then you should instead use $all, which is shorter syntax:
$endUserData = $mongoDb->find(array(
'active_status' => array( '$all' => array(1,2) )
));
I should add that unless you intend to match a document like this:
{ "active_status" => [1,2] }
The you do not in fact want $and at all, but rather you want $or or better yet $in for multiple possible values on the same field:
$endUserData = $mongoDb->find(array(
'active_status' => array( '$in' => array(1,2) )
));
This matches documents like this:
{ "active_status": 1 },
{ "active_status": 2 }
Imagine I have a MonogDB collection containing documents as follows:
{name: 'Some Name', components: {ARRAY OF ITEMS}}
How can I return the name and the count of items in components?
Do I have to use a map/reduce?
I am using PHP's Mongo extension.
EDIT: Snippet of current code in PHP (working) but I just want count of the components
$fields = array(
'name', 'components'
);
$cursor = $this->collection->find(array(), $fields);
$cursor->sort(array('created_ts' => -1));
if (empty($cursor) == true) {
return array();
} else {
return iterator_to_array($cursor);
}
Thanks,
Jim
You could use map-reduce or you could use a simple group query as follows. Since I am assuming that your name property is a unique key, this should work even though it isn't a reason that you'd normally use the group function:
db.test.group({
key: { name:true },
reduce: function(obj,prev) {
var count = 0;
for(k in obj.components)
count++;
prev.count = count;
},
initial: { count: 0}
});
You mentioned that you have an array of components, but it appears that you are storing components as an object {} and not and array []. That is why I had to add the loop in the reduce function, to count all of the properties of the components object. If it were actually an array then you could simply use the .length property.
In PHP it would look something like this (from the Manual):
$keys = array('name' => 1);
$initial = array('count' => 0);
$reduce =<<<JS
function(obj,prev) {
var count = 0;
for(k in obj.components)
count++;
prev.count = count;
},
JS;
$m = new Mongo();
$db = $m->selectDB('Database');
$coll = $db->selectCollection('Collection');
$data = $coll->group($keys, $initial, $reduce);
Finally, I would strongly suggest that if you are trying to access the count of your components on a regular basis that you store the count as an additional property of the document and update it whenever it changes. If you are attempting to write queries that filter based on this count then you will also be able to add an index on that components property.
You could use db.eval() and write the calculation in JavaScript.
Jim-
These are two separate operations; Unless you want to leverage PHP's count on the results you get which you would then do something like:
$m = new Mongo();
$db = $m->selectDB('yourDB');
$collection = $db->selectCollection('MyCollection');
$cursor = $collection->find(array(), array("name"=>1, "components"=>1));
foreach($cursor as $key){
echo($key['name'].' components: '.count($key['components']);
}
Ran across this today, If your using the new driver with aggregate you can do this in php, ( given this schema )
{name: 'Some Name', components: {ARRAY OF ITEMS}}
In PHP:
$collection = (new Client())->db->my_collection;
$collection->aggregate([
'$match' => ['name' => 'Some Name'],
'$group' => [
'_id' => null,
'total'=> ['$sum' => "\$components"]
]
]);
The trick here with PHP is to escape the $ dollar sign, this is basically what the mongo documentation says when using size or sum
https://docs.mongodb.com/manual/reference/operator/aggregation/size/
https://docs.mongodb.com/manual/reference/operator/aggregation/sum/
The problem I had is mongo puts fields in as "$field" and PHP doesn't like that at all because of the way it does variable interpolation. However, once you escape the $, it works fine.
I think for this particular case you'd need to do something similar but with $project instead of $group Like this
$collection = (new Client())->db->my_collection;
$collection->aggregate([
'$match' => ['name' => 'Some Name'],
'$project' => [
'name' => "\$name",
'total'=> ['$sum' => "\$components"]
]
]);
This is an old question but seeing as there is no answer picked, I'll just leave this here.
Is there a way to store an array as a document field and then query that array?
I've got a collection of items, which are tagged. I'd like to be able to search all items that match for example tags 55 and 67.
How would I achieve this?
First you have to create index file with the data in your array. The documentation covers how to create a new index.
so imagining your array look like
$data = array(
array(
'tag' => '55 67',
'content' => 'Lorem Ipsu 1',
'url' => 'http://foobar.net/content.php?id=1'
),
array(
'tag' => '32 67'
'content' => 'Lorem Ipsu 2',
'url' => 'http://foobar.net/content.php?id=2'
)
);
it would give something like that to create your index
// Create index
$index = Zend_Search_Lucene::create('/data/my-index');
foreach($data as $row){
$doc = new Zend_Search_Lucene_Document();
// Store document URL to identify it in the search results
$doc->addField(Zend_Search_Lucene_Field::Text('url', $row['url']));
// Store document TAGS
$doc->addField(Zend_Search_Lucene_Field::Text('tag', $row['tag']));
// Index document contents
$doc->addField(Zend_Search_Lucene_Field::UnStored('contents', $row['content']));
// Add document to the index
$index->addDocument($doc);
}
finally to query your index file
$index = Zend_Search_Lucene::open('/data/my_index');
$hits = $index->find('tag:55 AND tag:67');
foreach ($hits as $hit) {
echo $hit->score;
echo $hit->url;
echo $hit->tag;
}
Note
I am not really sure why you intend to use Lucene to do such work, if you just want a listing of article matching whatever tag would be more easy to do it with plain SQL queries.
After if want to know how Zend_Search_Lucene works that could be an example