Fetch a value from an array in a MongoDB collection - mongodb

Below is my MongoDB collection
{
"_id" : ObjectId("5b2a2ee19d332d0118b26dfe"),
"Name" : "Rock",
"Job" : [
{
"Id" : ObjectId("5b2b93c63629d0271ce366ae"),
"JobName" : "abc",
"JobTrack" : [
"123"
]
}
]
}
I want to fetch both ObjectId values
my $cursor = $custColl->find(
{ 'Job.JobName' => "abc", 'Job.JobTrack' => "123" },
{ '_id' => 1, 'Job.Id' => 1 }
);
while ( my $next = $cursor->next ) {
my $CustomerId = "$next->{_id}";
my $JobId = "$next->{'Job.Id'}";
say "$CustomerId => $JobId\n";
}
The result I got from above code as follows
5b2a2ee19d332d0118b26dfe =>
With this code I'm not able to get $JobId.

Assuming the query finds a document, $next is a Perl data structure that resembles your original JSON:
{
'Name' => 'Rock',
'_id' => bless( {
'value' => '5b2a2ee19d332d0118b26dfe'
}, 'MongoDB::OID' ),
'Job' => [
{
'JobName' => 'abc',
'JobTrack' => [
'123'
],
'Id' => bless( {
'value' => '5b2b93c63629d0271ce366ae'
}, 'MongoDB::OID' )
}
]
}
To get the job ID, you need to dereference that structure using Perl syntax, not MongoDB syntax:
my $JobId = "$next->{Job}[0]{Id}";

You need to access a specific element of the Job array. Because there is only one element in your example it must have an index of zero. Accordingly you need
my $JobId = "$next->{'Job.0.Id'}";

Related

MongoDb v4.2.1 aggregation - How to use join in php 7 code

I am working on PHP7 with MongoDB 4.2.
I am trying to Join tables using aggregation.
I am able to do on mongo console.
db.orders.aggregate([
{
$lookup: {
from: "items",
localField: "item", // field in the orders collection
foreignField: "item", // field in the items collection
as: "fromItems"
}
},
{
$replaceRoot: { newRoot: { $mergeObjects: [ { $arrayElemAt: [ "$fromItems", 0 ] }, "$$ROOT" ] } }
},
{ $project: { fromItems: 0 } }
])
and getting result as:
{ "_id" : 1, "item" : "almonds", "description" : "almond clusters", "instock" : 120, "price" : 12, "quantity" : 2 }
{ "_id" : 2, "item" : "pecans", "description" : "candied pecans", "instock" : 60, "price" : 20, "quantity" : 1 }
Same thing I want do in the PHP but not getting result:
My PHP code is:
<?php
public function demo_join() {
global $mng; // $mng = new MongoDB\Driver\Manager("mongodb://localhost:27017");
global $dbname;
$command = new MongoDB\Driver\Command([
'aggregate' => 'orders',
'pipeline' => [
['$lookup' => ["from" => "items","localField" => "items","foreignField" => "items","as" => "fromItems"]],
],
]);
//$cursor = $mng->executeCommand($dbname, $command);
try {
$cursor = $manager->executeCommand($dbname, $command);
} catch(MongoDB\Driver\Exception $e) {
echo $e->getMessage(), "\n";
exit;
}
return $cursor;
}
?>
and getting this error:
Uncaught Error: Call to a member function executeCommand() on null in $cursor = $manager->executeCommand($dbname, $command);
and some time
Uncaught MongoDB\Driver\Exception\CommandException: The 'cursor' option is required, except for aggregate with the explain argument in
Ok, I got the answer:
I added this line : 'cursor' => new stdClass
<?php
//mongo database join example
public function test_join() {
global $mng;
global $dbname;
$pipeline = [['$lookup' => ["from" => "items","localField" => "items","foreignField" => "items","as" => "fromItems"]]];
$aggregate = new \MongoDB\Driver\Command([
'aggregate' => 'orders',
'cursor' => new stdClass,
'pipeline' => $pipeline
]);
$cursor = $mng->executeCommand($dbname, $aggregate);
return $cursor;
}
?>
Now, I am able to get the result.

mongodb aggregation match date

I have data like
{
"_id" : ObjectId("5b63e593f033ab66fa25a142"),
"percent_change_1h" : 0.37,
"percent_change_24h" : -3.91,
"percent_change_7d" : -7.08,
"last_updated" : 1533273443,
"created_at" : "2018-08-03 05:18:11",
"updated_at" : "2018-08-03 05:18:11"
}
its have created_at date like this "2018-08-03 05:18:11"
but i can pass date in aggregation function like "2018-08-03"
data not get in this match
I can not use $gte or $lte becouse get only given date data
query is here
$date = "2018-08-15";
$filters = ['$match'=>[
'quotes'=>$quotes,
'created_at' => $date]
];
$join = ['$lookup'=>[
'from' => "cryptocurrencies_list",
'localField'=> "crypto_list_id",
'foreignField'=> "_id",
'as'=>"listdata"]
];
$limits = ['$limit'=>10];
$query = $detailscollection->aggregate([$filters,$join,$limits]);
You can try below aggregation
$detailscollection->aggregate([
[
'$addFields' => [
'date' => [
'$dateToString' => [
'date' => [
'$dateFromString' => [
'dateString' => '$created_at',
'timezone' => 'America/New_York'
]
],
'format' => '%Y-%m-%d'
]
]
]
],
[
'$match' => [
'date' => $date, 'quotes' => $quotes
]
]
])

How to apply correctly $limit and $skip in subfields?

I'm starting with mongodb and I'm finding many difficulties with the following scheme.
{
"_id" : "AAA",
"events" : [
{
"event" : "001",
"time" : 1456823333
},
{
"event" : "002",
"time" : 1456828888
},
{
"event" : "003",
"time" : 1456825555
},...
]
}
I want to get the events sorted by date and apply limit and skip.
I'm using the following query:
$op = array(
array('$match' => array('_id' => $userId)),
array('$unwind' => '$events'),
array('$sort' => array('events.time' => -1)),
array('$group' => array('_id' => '$_id',
'events' => array('$push' => '$events')))
//,array('$project' => array('_id' => 1, 'events' => array('$events', 0, 3)))
//,array('$limit' => 4)
//,array('$skip' => 3)
);
$result= Mongo->aggregate('mycollection', $op);
I have tried everything to filter $project or $limit and $skip but none of it works.
How should I apply the limit and skyp conditions in events?
If I do not apply the conditions of "limit" above the result is ordered correctly.
Result:
{ "waitedMS":0,
"result":[
{
"_id":"AAA",
"events":[
{
"event":"002",
"time":1456828888,
},
{
"event":"003",
"time":1456825555,
},
{
"event":"001",
"time":1456823333,
},...
}
],
"ok":1
}
Order correctly but I can not limit the number of results for paging.

remove element from embedded document in mongodb

I am using mongodb library for codeigniter.i want to delete element from embedded document. my collection is as follows-
{
"_id" : ObjectId("56503a272f170d30298b45ad"),
"gm_creation_time" : "2015-11-21 09:32:23",
"gm_favourites" : [
{
"gm_user_id" : "55f90ccf2f170d79048b4570",
"gm_id" : "56503a272f170d30298b45ad",
"date" : "2015-11-21 09:32:40"
}
],
"gm_members" : [
"560391de2f170d1e108b4574",
"55f90ccf2f170d79048b4570"
],
"gm_name" : "Sunny#ccs",
"gm_owner" : "55f90ccf2f170d79048b4570",
"gm_photo" : null,
"gm_posts" : [ ],
"gm_type" : "1",
"gm_updation_time" : "2015-11-21 09:32:40"
}
How can I delete from favorites according to gm_user_id. I am new to codeigniter+mongodb. please help
Use the $pull array modifier operator to remove all instances of a value or values that match a specified condition from an existing array.
The following mongo operation updates all documents in the collection to remove the object with "gm_user_id" property that has a value of "55f90ccf2f170d79048b4570" from the array gm_favourites:
db.collection.update(
{ },
{
"$pull": {
"gm_favourites": {
"gm_user_id": "55f90ccf2f170d79048b4570"
}
}
},
{ "multi": true }
);
This will translate to PHP as follows:
$connection = new Mongo();
$db = $connection->selectDB('dbname');
$collection = $db->selectCollection('collection_name');
$filter = array();
$remove_document = array(
'$pull' => array(
'gm_favourites' => array(
'gm_user_id' => '55f90ccf2f170d79048b4570',
)
)
);
$options['multiple'] = true;
$collection->update($filter, $remove_document, $options);
If you want to remove the embedded document based on gm_user_id use the following command. (Assuming the collection name is favorites):
db.test.update( {} , {$pull:{'gm_favourites':{'gm_user_id' : '55f90ccf2f170d79048b4570'}}})
The above command will remove the matching embedded document.

MongoDB MapReduce Emit Strangeness

I'm very much a noob when it comes to MapReduce and I have been pulling my hair out with this issue. Hopefully someone can give me a hand.
My Goal: Get the product revenue and a count of the units sold.
Transactions Collection sample document where i'm querying from:
{ "_id" : ObjectId( "xxxxxxxxxx" ),
"MerchantID" : { "$ref" : "merchants",
"$id" : ObjectId( "xxxxxxxx" ) },
"TransactionSocialKey" : "xxxxxxxx",
"PurchaseComplete: true,
"Products" : [
{ "ProductID" : { "$ref" : "products",
"$id" : ObjectId( "4ecae2b9cf72ab1f6900xxx1" ) },
"ProductPrice" : 14.99,
"ProductQuantity" : "1" },
{ "ProductID" : { "$ref" : "products",
"$id" : ObjectId( "4ecae2b9cf72ab1f690xxx2" ) },
"ProductPrice" : 14.99,
"ProductQuantity" : "1" } ],
"DateTimeCreated" : Date( 1321919161000 ) }
As you can see I have an embedded array called Products with the ProductID, Product Price, and Product Quantity.
My Map Function
map = function(){
if(this.PurchaseComplete === true){
this.Products.forEach(function(Product){
if(Product.ProductID.$id.toString() == Product_ID.toString()){
emit(Product_ID, {
"ProductQuantity" : Product.ProductQuantity,
"ProductPrice" : Product.ProductPrice,
"ProductID" : Product.ProductID.$id.toString()
});
}
});
}
}
So with this i'm only going to emit Transactions that were completed. If the Transaction was completed I'm looping through the Products array and if the Product.ProductID.$id is equal to the Product_ID that I set in the MapReduce Scope then I'm going to emit the Product from the set.
For testing sake I've set up my Reduce function as:
reduce = function(key, Product_Transactions){
return {"Transactions" : Product_Transactions};
}
For some odd reason i'm getting this sort of result:
[results] => Array
(
[0] => Array
(
[_id] => MongoId Object
(
[$id] => 4ecae2b9cf72ab1f6900xxx1
)
[value] => Array
(
[Transactions] => Array
(
[0] => Array
(
[Transactions] => Array
(
[0] => Array
(
[ProductQuantity] => 1
[ProductPrice] => 14.99
[ProductID] => 4ecae2b9cf72ab1f6900xxx1
)
[1] => Array
(
[ProductQuantity] => 1
[ProductPrice] => 14.99
[ProductID] => 4ecae2b9cf72ab1f6900xxx1
)
It Continues…
)
)
[1] => Array
(
[ProductQuantity] => 1
[ProductPrice] => 12.74
[ProductID] => 4ecae2b9cf72ab1f6900xxx1
)
[2] => Array
(
[ProductQuantity] => 1
[ProductPrice] => 12.74
[ProductID] => 4ecae2b9cf72ab1f6900xxx1
)
)
)
)
)
I'm not sure why I'm getting this odd embedded array. The emit key is always the same and never changes. I'm really lost for ideas on where to start trouble shooting. Any help or guidance would be appreciated.
Output of map should be in the same format that reduce consumes and produces. The idea is that reduce may run in parallel and/or against partially reduced results.
Here's how your code should look like (pseudo-code)
var map = function() {
if(some condition) {
emit(product_id, {Transactions: [{ // <= note the array here!
"ProductQuantity" : Product.ProductQuantity,
"ProductPrice" : Product.ProductPrice,
"ProductID" : ID
}]})
}
};
var reduce = function(key, vals) {
var result = {Transactions: []};
vals.forEach(function(v) {
v.Transactions.forEach(t) {
result.Transactions.push(t);
}
});
return result;
}