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

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

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

PHP MongoDB Driver and Aggregations

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.

Upsert using multiple key search

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

MongoDB groupby distinct sort together

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.

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