I have two collection rounds and summaries
A record in rounds looks like
{
"_id": "2018-04",
"name": "Round 2018-04"
}
A record in summaries look like
{
"phase": "round:2018-04",
"userId": NumberLong(66325),
}
I want to query summaries and lookup into rounds joining based on phase of summaries into _id of rounds
PROBLEM: It will be pretty simple if there was no prefix of round: in phase.
Is there anyway to do this?
This is my code so far.
$cursor = $this->mongo->selectCollection('summaries')->aggregate([
array('$match' => []),
array(
'$lookup' => [
'from' => 'rounds',
'localField' => 'phase',
'foreignField' => '_id',
'as' => 'roundDetail'
]
),
array(
'$unwind' => '$roundDetail',
),
array(
'$project' => [
'userId' => 1,
'roundDetail.name' => 1
]
)
]);
MongoDB version 3.4.16
You can use substrBytes to remove characters from the string.
$cursor = $this->mongo->selectCollection('summaries')->aggregate([
array('$match' => []),
array('$addFields' => [ 'phase' => [ '$substrBytes' => [ '$phase', 6, 7 ] ] ] ),
array(
'$lookup' => [
'from' => 'rounds',
'localField' => 'phase',
'foreignField' => '_id',
'as' => 'roundDetail'
]
),
array(
'$unwind' => '$roundDetail',
),
array(
'$project' => [
'userId' => 1,
'roundDetail.name' => 1
]
)
])
Related
i have collection page and page has many widgets:
page collection :
_id
name
slug,
widget_codes
widget collection :
_id
name
code
type
product_ids
category_ids
product collection:
_id
name
type
category collection:
_id
name
type
for retrieve data i use like this:
public function getData($page) {
return $page->raw(function ($collection) use ($page) {
return $collection->aggregate([
[
'$lookup' => [
'from' => 'widgets',
'localField' => 'widget_codes',
'foreignField' => 'code',
'as' => 'widgets',
]
],
[
'$match' => ['slug' => $page->slug]
]
]);
});
}
it works perfect and get widget data now i want to get product and category data with widget using that widget has product_ids and category_ids what query can i use.
You can use pipeline in $lookup for subquery the multiple tables
public function getData($page) {
return $page->raw(function ($collection) use ($page) {
return $collection->aggregate([
[
'$match' => ['slug' => $page->slug]
],
[
'$lookup' => [
'from' => 'widgets',
"let"=> [ "widget_codes"=> "$widget_codes" ],
"pipeline"=> [
[ "$match"=> [ "$expr"=> [ "$in"=> ["$_id", "$$widget_codes"] ]]],
[
'$lookup' => [
'from' => 'category',
'localField' => 'category_ids',
'foreignField' => '_id',
'as' => 'categories',
]
],
[
'$lookup' => [
'from' => 'product',
'localField' => 'product_ids',
'foreignField' => '_id',
'as' => 'products',
]
]
],
'as' => 'widgets',
]
]
]);
});
}
I'm trying to select data from few documents and output in nested arrays.
Aggregate:
$aggBuilder = $this->documentManager->getDocumentCollection(User::class);
$outputData = $aggBuilder->aggregate([
['$match' => [
'_id' => ['$in' => $usersId]
]
],
['$unwind' => '$articles'],
['$lookup' => [
'from' => 'articles',
'localField' => 'articles._id',
'foreignField' => '_id',
'as' => 'article',
]],
['$unwind' => '$article'],
['$lookup' => [
'from' => 'comments',
'localField' => 'comments._id',
'foreignField' => 'article_id',
'as' => 'article.comment'
]],
['$group' => [
'_id' => [
'id' => '$_id',
'name' => '$name',
'desc' => '$desc',
],
'articles' => ['$addToSet' => [
'id' => '$article._id',
'title' => '$article.title',
'content' => '$article.content',
'comments' => ['id' => $article.comment.id', 'content' => '$article.comment.content'],
]],
]]
],
[
'cursor' => [
'batchSize' => 101,
],
]);
dd($outputData->toArray());
The problem is in part where I try to in every article get collection of comments for this article.
Some reason output looks this:
'Andy Jones' = [
'Article First' = [
'id' = 'sdgdf76g8df',
'title' = 'First Article'
'content' = 'Contetn of article'
'comments' = [
'id' = [
'dfdh54gdfter',
'32gdfhfgh43et',
'34te3gdfgerdt'
],
'content' = [
'content for first article',
'content for second article',
'content for third article'
]
]
]
]
As you see comments are splited in two arrays. One for 'id' and one for 'content'.
What I want is separate array for every comment and in that array data from single comment. Like bellow:
'comments' = [
[0] = [
'id' = 'dfdh54gdfter',
'content' = 'Lorem ipsum 1',
],
[1] = [
'id' = 'dfdg4554er',
'content' = 'Lorem ipsum 2',
],
[2] = [
'id' = 'dfdh54gdfter',
'content' = 'Lorem ipsum 3',
],
]
Thank you.
I have two tables in mongodb database
activityCountTbl contains data like
{
"_id": ObjectId("5c234f7e3250041280000ca3"),
"activityId": ObjectId("5c0e27ee590a06bf08003c33"),
"weekgroupId": ObjectId("5bfbddbcbb2c5645f8001495"),
"squadronId": ObjectId("5bfc7b7ebb2c56c320002a0a"),
"attendingCount": NumberInt(6),
....
}
{
"_id": ObjectId("5c234f7e3250041280000ca3"),
"activityId": ObjectId("5c0e27ee590a06bf08003c33"),
"weekgroupId": ObjectId("5bfbddbcbb2c5645f8001496"),
"squadronId": ObjectId("5bfc7b7ebb2c56c320002a0a"),
"attendingCount": NumberInt(6),
....
}
squadronTbl contains data like
{
"_id": ObjectId("5c19ccb7590a060691000554"),
"squadronCode": "336",
"squadronName": "336TRS",
}
{
"_id": ObjectId("5c19ccb7590a060691000556"),
"squadronCode": "337",
"squadronName": "337TRS",
}
I am storing count details of a particular activity of a weekgroup in activityCountTbl. I am performing lookup on squadronTbl with activityCountTbl
for fetching squadrons details of a particular weekgroup. The below code is not working.
When I comment/delete the $query code, it fetches all the squadrons of all weekgroups.
$query = ["ActivityArray.weekgroupId" => new MongoDB\BSON\ObjectID("5bfbddbcbb2c5645f8001495"), "ActivityArray.funRun" => "Yes"];
$pipeline = array(
[
'$match' => $query
],
[
'$lookup' => [
'from' => 'activityCountTbl',
'localField' => '_id',
'foreignField' => 'squadronId',
'as' => 'ActivityArray'
]
],
['$project' => [
'_id' => 1.0,
'squadronName' => 1.0,
'ActivityArray' => 1.0
]],
);
return $this->db->squadronTbl->aggregate($pipeline)->toArray();
Please help !!!
$query = ["ActivityArray.weekgroupId" => new MongoDB\BSON\ObjectID("5bfbddbcbb2c5645f8001495"), "ActivityArray.funRun" => "Yes"]
$pipeline = array(
[
'$match' => []
],
[
'$lookup' => [
'from' => 'activityCountTbl',
'localField' => '_id',
'foreignField' => 'squadronId',
'as' => 'ActivityArray'
]
],
[
'$match' => $query
],
['$project' => [
'_id' => 1.0,
'squadronName' => 1.0,
'ActivityArray' => 1.0
]],
);
something like that
I have code like this:
$users = User::raw(function ($collection) use($profession, $userId, $skip, $pageSize) {
return $collection->aggregate([
[
'$lookup' => [
'from' => 'user_profile',
'localField' => 'uid',
'foreignField' => 'user_id',
'as' => 'profile'
]
],
[
'$match' => [
'profile.field_of_work' => $profession['id'],
'uid' => ['$ne' => $userId]
],
],
['$skip' => $skip],
['$limit' => $pageSize]
]);
});
from there, how to add where clause like this:
::where('name', 'like', '%test%');
I dont know how to using lookup in mongodb and I just know the basic pattern of eloquent.
Thank you
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'
]
]
]
];