I've thoroughly searched on the internet for this but haven't found a solution.
Problem : I want to update the quantity in this document. Criteria - itemId=126260, accessDays=30
`{
"_id" : ObjectId("547acfa95ca86bec2e000029"),
"session_id" : "1111",
"email" : "aasdasda#sdfsd.com",
"isProcessed" : 0,
"couponApplied" : "",
"countryId" : 2,
"items" : [
{
"itemId" : 126260,
"batchId" : 102970,
"accessDays" : null,
"quantity" : 2
},
{
"itemId" : 126260,
"batchId" : null,
"accessDays" : 30,
"quantity" : 2
}
]
}`
I am trying to do this using PHP :
`$condition = array( "session_id"=>'1111', 'items.itemId'=>126260, 'items.accessDays'=>30);
$new_values = array( '$set' => array("items.$.quantity" => 10) );
$cart_coll->update($condition, $new_values);`
But when I run this code, it updates the first nested object instead of the second.
What am I doing wrong here ? Does mongodb not consider multiple conditions in nested objects ?
You need to use $elemMatch to get the array marker to be in the right place. So your $query becomes
$condition = array( "session_id"=>'1111',
"items" => array(
'$elemMatch'=>array("itemId"=>126260, 'accessDays'=>30)));
Related
I have Inserted records in mongodb collection/table. everything working fine if i pass data which is available in collection like StoreId = 1
Problem: if i search data which is not available in collection like StoreId=3 then it is taking too long time to response why???? How do i simplify this issue?
Insert Data:
$data = array();
$data[] = array("StoreId" => "1","StoreName" => "abc");
$data[] = array("StoreId" => "2","StoreName" => "xyz");
$db->test->insertMany($data);
Fetch Records:
$arrFind = array(
'$and' => array(
array(
'StoreId' => "1"
),
array(
'StoreName' => array(
'$regex' => '^ab',
'$options' => 'i'
)
)
)
);
$projection = array("_id" => false);
$result = $db->test->find($arrFind,['limit'=>$data['Count'], 'projection' => $projection ]);
$array1 = iterator_to_array($result, false);
echo "<pre>";
print_r($array1);
above example working find returns output very quickly, but if i pass StoreId=3 then it is taking too long time to response blank output.
Mongodb:
db.test.find( { StoreId: "1" } ).pretty() //returns output quickly
db.test.find( { StoreId: "3" } ).pretty() //taking too-long time for blank output.
explain:
db.test.find( { StoreId: "3" } ).explain(true)
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "mydb.test",
"indexFilterSet" : false,
"parsedQuery" : {
"StoreId" : {
"$eq" : "3"
}
},
"winningPlan" : {
"stage" : "COLLSCAN",
"filter" : {
"StoreId" : {
"$eq" : "3"
}
},
"direction" : "forward"
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 0,
"executionTimeMillis" : 35083,
"totalKeysExamined" : 0,
"totalDocsExamined" : 6816823,
"executionStages" : {
"stage" : "COLLSCAN",
"filter" : {
"StoreId" : {
"$eq" : "3"
}
},
"nReturned" : 0,
"executionTimeMillisEstimate" : 34087,
"works" : 6816825,
"advanced" : 0,
"needTime" : 6816824,
"needYield" : 0,
"saveState" : 53988,
"restoreState" : 53988,
"isEOF" : 1,
"invalidates" : 0,
"direction" : "forward",
"docsExamined" : 6816823
},
"allPlansExecution" : [ ]
},
"serverInfo" : {
"host" : "Neha-PC",
"port" : 27017,
"version" : "3.6.3",
"gitVersion" : "9586e557d54ef70f9ca4b43c26892cd55257e1a5"
},
"ok" : 1
}
Hi looking at you question , it examined around 6816823 record , it seems there is no secondary index has been created
you need to create the index on "StoreId" reduced the lookup
u can check what all the index has been created for your collection using following command
db.test.getIndexKeys();
To create index you can use following command
db.test.createIndex( { StoreId: 1 } );
after creating the index on your collection try to run the query , it should be fast
for more info
https://docs.mongodb.com/manual/reference/method/db.collection.createIndex/
Because you don't have any indexes which can be used for this query, so MongoDB need to check every document in the collection. The collection scan ("COLLSCAN") is pretty slow on big collections. You need to create an index from StoreId element.
I am at my first steps with mongoDB and php, trying to figure out how aggregations works. I have an approximate idea on how to use them from the command line but I am trying to translate this for the php driver. I am using the restaurants dexample DB, a list of records like this
{
"_id" : ObjectId("59a5211e107765480896f3f8"),
"address" : {
"building" : "284",
"coord" : [
-73.9829239,
40.6580753
],
"street" : "Prospect Park West",
"zipcode" : "11215"
},
"borough" : "Brooklyn",
"cuisine" : "American",
"grades" : [
{
"date" : ISODate("2014-11-19T00:00:00Z"),
"grade" : "A",
"score" : 11
},
{
"date" : ISODate("2013-11-14T00:00:00Z"),
"grade" : "A",
"score" : 2
},
{
"date" : ISODate("2012-12-05T00:00:00Z"),
"grade" : "A",
"score" : 13
},
{
"date" : ISODate("2012-05-17T00:00:00Z"),
"grade" : "A",
"score" : 11
}
],
"name" : "The Movable Feast",
"restaurant_id" : "40361606"
}
I just want to count how many restaurants for location, what I am doing is
$client = new MongoDB\Client("mongodb://localhost:27017");
$collection = $client->myNewDb->restaurants;
$results = $collection->aggregate(
[
'name' => '$name'
],
[
'$group' => [
'cuisine' => ['sum' => '$sum']
]
]
);
and I am getting this error
Fatal error: Uncaught exception 'MongoDB\Exception\InvalidArgumentException'
with message '$pipeline is not a list (unexpected index: "name")'
any idea? I can't find any good documentation on php.net.
thanks
M
Just take a look into documentation, and you will see, that the pipelines must be passed as an array.
The aggregate method accepts two parameters $pipelines and $options (public function aggregate(array $pipeline, array $options = [])).
Also as was mentioned before, the $group must have the _id element.
Groups documents by some specified expression and outputs to the next
stage a document for each distinct grouping. The output documents
contain an _id field which contains the distinct group by key. The
output documents can also contain computed fields that hold the values
of some accumulator expression grouped by the $groupās _id field.
$group does not order its output documents.
https://docs.mongodb.com/manual/reference/operator/aggregation/group/
So your code must look like this:
$results = $collection->aggregate([
[
'$group' => [
'_id' => '$cuisine',
'sum' => ['$sum' => 1],
'names' => ['$push' => '$name']
]
]
]);
This code groups documents by cuisine element, counts the items and collects all name values into array.
Ok, guys. As most of you might know, there is this new MongoDB Driver for PHP 7 out there. I was trying it out. I got stuck at this query here :
There is a collection like this:
{
"_id" : ObjectId("592d026e2a5e742704e60055"),
"name" : "One",
"conn" : [
{
"_id" : ObjectId("592d03cd3c83d5265c004d0b"),
"name" : "MongoDB Fans",
"comments" : "nice!"
},
{
"_id" : ObjectId("592d06513c83d5265c004d17"),
"name" : "SQL Fans",
"comments" : "not so nice!"
}
]
},
{
"_id" : ObjectId("592d0eec2a5e742704e60056"),
"name" : "Two",
"conn" : [
{
"_id" : ObjectId("592d0ef13c83d5265c004d37"),
"name" : "Cassandra Fans",
"comments" : "spooky!"
}
]
}
Now, what I want to achieve is this:
1. Find all "conn" fields (irrespective of which document they belong to) that contain a user input (say "xyz") in "name" as a sub-string.
2. Project the selected "conn" fields out.
I have tried using the following filters and options without success (Almost all of these return all the "conn" subsets instead of only the filtered subsets):
$filters = ["conn.name" => new MongoDB\BSON\Regex($name,'i')];
$options = ["projection" => ["_id" => 0,"conn" =>1];
$filters = ["conn" => ["\$all" =>["name" => new MongoDB\BSON\Regex($name,'i')]]];
$options = ["projection" => ["_id" => 0,"conn" =>1];
$filters = ["conn.name" => '/'.$name.'/i'];
$options = ["projection" => ["_id" => 0,"conn" =>1];
NOTE: I am using PHP 7 and the latest mongod PECL extension
i have mongodb 1 collections structure like this-
{
"_id" : ObjectId("54d34cb314aa06781400081b"),
"entity_id" : NumberInt(440),
"year" : NumberInt(2011),
}
{
"_id" : ObjectId("54d34cb314aa06781400081e"),
"entity_id" : NumberInt(488),
"year" : NumberInt(2007),
}
{
"_id" : ObjectId("54d34cb314aa06781400081f"),
"entity_id" : NumberInt(488),
"year" : NumberInt(2008),
}
{
"_id" : ObjectId("54d34cb314aa067814000820"),
"entity_id" : NumberInt(488),
"year" : NumberInt(2009),
}
{
"_id" : ObjectId("54d34cb314aa067814000827"),
"entity_id" : NumberInt(489),
"year" : NumberInt(2009),
}
so in output i want that i should get "entity_id" with max "year" only .(suppose with "488" entity_id "year" should be 2009).
i have tried writing query
$fin_cursor = $db->command(array(
"distinct" =>"Profit_and_Loss",
"key" =>'entity_id',
"query" => array(array('$and'=>$financial_pl_search_array),array('$sort'=>array("year"=>-1))),
));
in output i want 2 fields "entity_id" and "year".
can anyone suggest me best way of doing it.
Thanks in advance.
You're better of using .aggregate() to do this. It's also a direct method on the collection objects in modern versions of the driver:
$result = $db->collection('Profit_and_loss')->aggregate(array(
array( '$group' => array(
'_id' => '$entity_id',
'year' => array( '$max' => '$year' )
))
));
The .distinct() command only runs over a single field. Other forms require JavaScript evaluation as you have noted and run considerably slower than native code.
I have bunch of documents on mongodb, and this is a dummy insert
array (
'_id' => new MongoId("51a449866803fa680a000002"),
'a' => 'dweddwe',
'b' => 'asdasdad',
'c' =>
array (
'0' => 'car',
),
'u' => '1',
'x' =>
array (
'0' => '51a0c0356803fa890a000003',
'1' => '51a0c0356803fa890a000003',
),
'y' => 'merto',
)
I have more than 100 inserted documents in my mongo database, the problem is, when I use this code and index like this x_1__id_1 or in any other ways, I always get [scanAndOrder] => 1, I have no idea what might be the problem or solution, how can I sort it in an efficient way ? thank you :)
$m->cars->post->find(array("x" => array('$in' => $mendor["t"])))->limit(10)->sort(array("_id" => -1))->explain();
this is $mendor["t"],
't' =>
array (
'0' => '519f2de16803fabd0d000001',
'1' => '51a0bf996803fa890a000001',
'2' => '519f2db96803fad20d000001',
'3' => '519f1cc56803fa960d000001',
),
Compund indexes are not useable for reverse ordering, but have no worries about it will not help in this case probably if you have in $mendor["t"] a real list.
I made a test collection called t with simple documents like :
{ "_id" : ObjectId("51a4c2c75e0733e8428ab2c0"), "x" : [ 1, 2, 3, 4 ] }
{ "_id" : ObjectId("51a4c2c95e0733e8428ab2c1"), "x" : [ 1, 2, 3, 6 ] }
{ "_id" : ObjectId("51a4c2cd5e0733e8428ab2c2"), "x" : [ 1, 4, 3, 6 ] }
I created the index : x_1__id_1
For the query:
db.t.find({x:3}).hint("x_1__id_1").sort({_id:1}).explain()
{
"cursor" : "BtreeCursor x_1__id_1",
"isMultiKey" : true,
"n" : 14,
"nscannedObjects" : 14,
"nscanned" : 14,
"nscannedObjectsAllPlans" : 14,
"nscannedAllPlans" : 14,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"x" : [
[
3,
3
]
],
"_id" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
},
"server" : ""
}
So it works as you like your query to work but :
db.t.find({x:{$in:[3,4]}}).hint("x_1__id_1").sort({_id:1}).explain()
{
"cursor" : "BtreeCursor x_1__id_1 multi",
"isMultiKey" : true,
"n" : 16,
"nscannedObjects" : 28,
"nscanned" : 28,
"nscannedObjectsAllPlans" : 28,
"nscannedAllPlans" : 28,
"scanAndOrder" : true,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"x" : [
[
3,
3
],
[
4,
4
]
],
"_id" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
},
"server" : ""
}
This is sort of reasonable while the multikey index which is used, is store as separated index keys the values in the array. See documentation: http://docs.mongodb.org/manual/core/indexes/#multikey-indexes
So the different parts which where collected from the different keys will be merged by the engine and than sorted. If you use a criteria which is like my first query,so instead of an array just search for one value. Than it will scanAndOrder : false. Probably you have to make an x_1_id-1 index.
There is a workaround but it is ugly a bit. If you use an or clause for the query than every part of the or list will use separately an index usage. So instead of using the in:[] condition, use or:[] and define as many different queries as many values you have in your $mendor["t"] array. In mongoshell did not worked, but i am sure it should, maybe i missed something.
You have a compound index on x, _id. The ordering of the _id is not absolute but within the context of an x value. In your query you are selecting a set of documents for particular x values and then ordering by just _id. So to get you the order it has to actually sort the results based on _id values as opposed to just using index order. That is what you see scan and order to be true. Hope this helps.