Query in mongo with $in operator - mongodb

I have one collection which contain documents with following structure:
array (
'_id' => new MongoId("54369e2904f7055598463483"),
'user' => '123',
'model' =>
array (
'test' =>
array (
'0' => 'test1',
'1' => 'test2',
'2' => 'test3',
),
),
)
And if I do the next query in Rock Mongo I got the results.
array(
'user' => array(
'$in' => array(
'0' => '123'
)
)
)
But if I try to fetch documents which have for example key => pair value '0' => 'test1' & '1' => 'test2' I don't get any data with the next query:
array(
'model' => array(
'test' => array(
'$in' => array(
'0' => 'test1',
'1' => 'test2',
)
)
)
)
Where I'm making mistake?
Thanks in advance

PHP's array/hash mixup makes your example a little hard to read and reason about. But here's what your model looks like in Mongo's native syntax (a language which makes a distinction between lists and maps):
{
"_id": ObjectId(...),
"user": 123,
"model": {"test": ["test1", "test2", "test3"]}
}
So you want to query on model.test (nested document). Using Mongo's native syntax, you'd do the following:
collection.find({"model.test": {"$in": ["test1", "test2"]})
See http://docs.mongodb.org/manual/reference/method/db.collection.find/ for more info.

Related

Case insensitive search inside projection condition

The data in hotel table is stored like
{
_id: ....,
HotelName: ...,
MasterKeyDetails:[
{
MasterKeyId: 36K1,
...
},
{
MasterKeyId: 36J1,
...
}
]
}
I have written below query
$cursor = $this->collection->aggregate(array(
array(
'$match' => array(
"_id" => new MongoDB\BSON\ObjectID($this->id)
)
),
array(
'$project' => array(
'MasterKeyDetails' => array(
'$filter' => array(
'input' => '$MasterKeyDetails',
'as' => 'room',
'cond' => array(
'$eq' => array('$$room.MasterKeyId', $this->MasterKeyId)
)
)
),
)
)
)
)->toArray();
It is searching fine. It searches when $this->MasterKeyId contains 36K1, but does not search when $this->MasterKeyId contains 36k1. I want it should fetch despite of case sensitive data...
Please help!!!
You can use $toUpper to normalise the data:
$cursor = $this->collection->aggregate(array(
array(
'$match' => array(
"_id" => new MongoDB\BSON\ObjectID($this->id)
)
),
array(
'$project' => array(
'MasterKeyDetails' => array(
'$filter' => array(
'input' => '$MasterKeyDetails',
'as' => 'room',
'cond' => array(
'$eq' => array(array('$toUpper' =>'$$room.MasterKeyId'), $this->MasterKeyId)
)
)
),
)
)
)
)->toArray();
In the same way you make sure the data you have to supply for comparison is also in the same case. There is also $toLower if you prefer that way.
As yet there is no other "case insensitive match" function you can use as part of an aggregation pipeline, so "normalizing" is the current approach.

Get sum of quantity in mongodb using yii2 framework

How can i sum of quantity using mongodb query in yii2?
In my database there are entries like below:
{
'_id': ObjectId("560e36f91e4acbf113d14f1f"),
'user_id': '55ded7c31e4acbea3c8b4567',
'money': '1.99',
'quantity': '1',
'purchased_date_time': '2015-10-02 07:49:13'
}
{
'_id': ObjectId("560e36f71e4acbf113d14f1e"),
'user_id': '55ded7c31e4acbea3c8b4567',
'money': '1.99',
'quantity': '1',
'purchased_date_time': '2015-10-02 07:49:11'
}
{
'_id': ObjectId("560d17381e4acbf013d14f1e"),
'user_id': '55ded7c31e4acbea3c8b4567',
'money': '4.99',
'quantity': '3',
'purchased_date_time': '2015-10-01 11:21:28'
}
I want to sum of quantity where user_id = 55ded7c31e4acbea3c8b4567.
What i tried is:
$collection = Yii::$app->mongodb->getCollection('purchase');
$result = $collection->aggregate(
array( '$match' => array( 'user_id' => '55ded7c31e4acbea3c8b4567') ),
array( '$group' => array( '_id' => NULL,
'quantity' => array( '$sum' => (int)'$quantity' )
))
);
But always i am getting this result:
<pre>Array
(
[0] => Array
(
[_id] =>
[quantity] => 0
)
)
</pre>
Can anyone help?
Remove int then after check......
I solved my issue after remove it
$collection = Yii::$app->mongodb->getCollection('purchase');
$result = $collection->aggregate(
array( '$match' => array( 'user_id' => '55ded7c31e4acbea3c8b4567') ),
array( '$group' => array( '_id' => NULL,
'quantity' => array( '$sum' => '$quantity' )
))
);

MongoDB get data from files from gridFS with aggregate function

Is it possible to get the files from a gridFS mongo database with a aggregate query?
I have the following query:
$ops = array(
array(
'$match' => array(
"_id" => array('$lt' => new MongoId($id)),
"data.VisionId" => (string)$visionId,
"data.GroepNummer" => (string)$groepnummer,
"data.TypeFile" => ucfirst($typefile),
'data.Datum' => array('$gt' => $new_date, '$lte' => $datum),
)
),
array(
'$sort' => array(
"uploadDate" => -1,
)
),
array(
'$limit' => 1000
),
array(
'$group' => array(
"_id" => array("Datum" => '$data.Datum',),
"FirstId" => array('$first' => '$_id'),
),
),
);
$result = $gridFS->aggregate($ops);
With a foreach I get the result from this aggregate.
But how do I get the data from the file.
(with a normal query i do it like $obj2->getBytes();)

PHP mongo - projection on particular array value

I have the following query:
$aggregate = [
['$unwind' => '$positions'],
['$match' => ['positions.banner_params.project_location_id' => (int)$projectId]],
[
'$project' => [
'page_id' => '$_id',
'position_id' => '$positions.id',
'page' => [
'website_id' => '$website_id',
'rate_tic' => '$rate_tic',
],
'banner_params' => [
'title' => '$positions.banner_params.title',
'tmpl_id' => '$positions.banner_params.tmpl_id'
],
'tmpl' => '$positions.tmpls',
'_id' => 0
]
],
];
$rows = $collection->aggregate($aggregate);
It returns such result:
[0] => Array
(
[page_id] => MongoId Object
(
[$id] => 5527a3a276098d86ae9aa3aa
)
[position_id] => 1
[page] => Array
(
[website_id] => 41
[rate_tic] => 10
)
[banner_params] => Array
(
[title] => My Title
[tmpl_id] => 2
)
[tmpl] => Array
(
[0] => Array
(
[id] => 1
[width] => 500
[height] => 100
)
[1] => Array
(
[id] => 2
[width] => 160
[height] => 400
)
[2] => Array
(
[id] => 7
[width] => 384
[height] => 115
)
)
)
How do I get into the tmpl only the template that match the banner_params.tmpl_id?
first let me sure if i understand it correctly. you want to filter items in the [tmpl] => Array by [id].
you cannot do that directly as the [tmpl] is an embedded object however as the aggregate is a pipeline function you can convert the current output the way you can filter and with $unwind then filter it again with $match and finally get the document as you wanted with $group. Something like below code should achieve what you want;
$aggregate = [
['$unwind' => '$positions'],
['$match' => ['positions.banner_params.project_location_id' => (int)$projectId]],
[
'$project' => [
'page_id' => '$_id',
'position_id' => '$positions.id',
'page' => [
'website_id' => '$website_id',
'rate_tic' => '$rate_tic',
],
'banner_params' => [
'title' => '$positions.banner_params.title',
'tmpl_id' => '$positions.banner_params.tmpl_id'
],
'tmpl' => '$positions.tmpls',
'_id' => 0
]
],
['$unwind' => '$tmpl'], // makes every item as a colection
['$match' => ['tmpl.id' => (int)$your id]], //filter the records
['$group' => ['_id' => '$page_id', tmpl:{$push:"$tmpl"} ]] // rebuild collection as you wanted you can use a compound _id if this is not enough
//if you don t want to see _id apply another projections to change it.
];
$rows = $collection->aggregate($aggregate);
Might have some errors but this is the logic you should implement.
EDIT:
There is also $redact DOC to remove items in sub documents please see the example.
Restricts the contents of the documents based on information stored in
the documents themselves.
Well, thanks to Onur TOPAL's advice I found the solution. One more $unvind followed by $redact did the job.
$aggregate = [
['$unwind' => '$positions'],
['$match' => ['positions.banner_params.project_location_id' => (int)$projectId]],
[
'$project' => [
'page_id' => '$_id',
'position_id' => '$positions.id',
'page' => [
'website_id' => '$website_id',
'rate_tic' => '$rate_tic',
],
'banner_params' => [
'title' => '$positions.banner_params.title',
'tmpl_id' => '$positions.banner_params.tmpl_id'
],
'tmpl' => '$positions.tmpls',
'_id' => 0
]
],
['$unwind' => '$tmpl'],
[
'$redact' => [
'$cond' => [
'if' => ['$eq' => ['$tmpl.id', '$banner_params.tmpl_id']],
'then' => '$$KEEP',
'else' => '$$PRUNE'
]
]
]
];

How to make this MongoDB aggregation return key:value?

I have this aggregation:
$out = $db->stats->aggregate (
array('$match' => $where),
,array( '$group' =>
array( "_id" => '$traffic.source',
'count'=> array('$sum' => 1)
)
)
,array( '$project' =>
array( "_id" => 0,
'type' => '$_id',
'count' => '$count'
)
)
);
which returns an array with:
[{type:sourceA, count:2},{type:sourceB, count:6}...]
Is it possible to make it return:
[sourceA:2, sourceB:6,....] without looping the array afterwords?