Upsert using multiple key search - php

I have the following mongodb structure
{
"_id" : 18536,
"billing" : {
"patientinfo" : {
"patient_id" : "120196"
},
"billinginfo" : {
"billingid" : "B1"
},
"receiptinfo" : [ ]
}
}
I want to insert array ("receipt_id"=>"R1") in receiptinfo Once one value is inserted again I have to insert another one eg: ("receipt_id"=>"R2").
I have tried the following code which is not working:
$updatereceipt =$collection->update(
array('_id' => (int)$id,'billing.receiptinfo.receipt_id'=>$receiptid),
array('$set' => array('billing.receiptinfo'=>array('receipt_id' => $receiptid))),
array("upsert"=>true)
);

Related

Parse Server Aggregation using PHP SDK

I'm trying to build an aggregation query in Parse's PHP SDK, and I'm stuck in the "lookup" area, I saw a JS example regarding this but it doesn't work in my case.
I have a table of users, which contains a "Tags" field of type Array, the array is actually an array of pointers, that point to a separate Tag class.
What I'm trying to achieve is to list most popular Tags based on their usage, so basically I need to query the users class and group the Tags that exist in the array, I already achieved this, but I'm stuck with the lookup part, the query currently returns an array of Tags pointers, what I want is to pull the object of those pointers.
Here's what I have currently:
$query = new ParseQuery('_User');
$pipeline = [
'project' => ['tags' => 1],
'unwind' => '$tags',
'group' => [
'objectId' => '$tags.objectId',
'count' => ['$sum' => 1]
],
'sort' => [ 'count' => -1],
'limit' => 10,
];
try {
return $query->aggregate($pipeline);
} catch (ParseException $ex) {
return $ex->getMessage();
}
And here's a snippet of what the _User collection looks like:
{
"_id" : "5BuBVo2GD0",
"email" : "test#test.com",
"username" : "test#test.com",
"lastname" : "Doe",
"firstname" : "John",
"_created_at" : ISODate("2017-01-23T09:20:11.483+0000"),
"_updated_at" : ISODate("2019-02-15T02:48:30.684+0000"),
"tags" : [
{
"__type" : "Pointer",
"className" : "Tag",
"objectId" : "St2gzaFnTr"
},
{
"__type" : "Pointer",
"className" : "Tag",
"objectId" : "LSVxAy2o74"
}
],
"_p_country" : "Country$4SE8J4HRBi",
}
And the Tag collection looks like this:
{
"_id" : "St2gzaFnTr",
"name" : "Music",
"_created_at" : ISODate("2018-10-22T20:00:10.481+0000"),
"_updated_at" : ISODate("2018-10-22T20:00:10.481+0000")
}
Any help would be appreciated!
Thanks in advance
Not sure if this is a direct answer, but here's a working aggregation on tags sorting for freq...
public function tagHistogram(Request $request, Response $response, array $args): Response {
$pipeline = [
'unwind' => '$tags' ,
'sortByCount' => '$tags',
'limit' => 1000,
];
$query = new ParseQuery('Product');
$result = $query->aggregate($pipeline);
$result = array_map(
function ($e) {
$e['name'] = $e['objectId'];
unset($e['objectId']);
return $e;
},
$result
);
return $response->withJson($result);
}

too long time for response in mongodb if field value is not available

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.

PHP MongoDB Driver Query Only Specific Field From All Documents In Collection

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

Trouble with converting working MongoDB aggregation pipeline query into PHP

I'm using MongoChef to construct an aggregation pipeline command that performs a $match, then a $group then a $project.
The following code produces the correct output and is confirmed working in MongoDB itself:
db.collection_name.aggregate(
[
{
$match: {
":energy_mon_id" : 9
}
},
{
$group: {
"_id" : {
"Date" : "$:date"
},
"avg_voltage_a" : {
"$avg" : "$:voltage_a"
},
"avg_voltage_b" : {
"$avg" : "$:voltage_b"
},
"avg_voltage_c" : {
"$avg" : "$:voltage_c"
}
}
},
{
$project: {
"avg_volt" : {
"$add" : [
"$avg_voltage_a",
"$avg_voltage_b"
]
}
}
},
{
$match: {
}
}
]
);
The output that is produced is this (note that the avg_volt values are integers):
{ "_id" : { "Date" : "2016-06-06" }, "avg_volt" : 779 }
{ "_id" : { "Date" : "2016-06-08" }, "avg_volt" : 779 }
Now the issue I'm faced with is getting this to run correctly in PHP.
My code in PHP is below:
$collection = $this->db->testdb->collection_name;
$aggrCommand = array(
array(
'$match' => array( ":energy_mon_id" => 9)
),
array(
'$group' => array(
"_id" => array(
"Date" => "$:date"
),
"avg_voltage_a" => array(
'$avg' => "$:voltage_a"
),
"avg_voltage_b" => array(
'$avg' => "$:voltage_b"
),
"avg_voltage_c" => array(
'$avg' => "$:voltage_c"
),
)
),
array(
'$project' => array(
"avg_volt" => array(
'$add' => ["$avg_voltage_a","$avg_voltage_b" ]
)
)
)
);
$list = $collection->aggregate( $aggrCommand);
The error I get is for this very last line when I try to submit a GET request via postman:
Slim Application Error
The application could not run because of the following error:
Details
Type: MongoDB\Driver\Exception\RuntimeException
Code: 16554
Message: $add only supports numeric or date types, not String
File: C:\wamp\www\DRM\vendor\mongodb\mongodb\src\Operation\Aggregate.php
Line: 168
This makes no sense at all since the output in MongoDB is an integer value, and I can't spot any errors in my conversion to PHP.
One thing to note is that my field names do actually contain a colon at the front (its not a mistake), but I don't think that is the issue here.
I'm really stumped with this, can someone provide any advice on how to figure this issue out? The output from my MongoDB command is clearly not a string, yet in PHP it says the values of avg_voltage_a and avg_voltage_b are strings. This makes no sense at all.
Try with single quotes in your "$add" statement to prevent PHP interpreting "$avg_voltage_a" as a variable :
'$add' => ['$avg_voltage_a','$avg_voltage_b' ]

PHP mongodb update on nested array with multiple conditions

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)));

Categories