collection not add pushing to subarray - php

I am using MongoDB and in the past I have been able to use the following to insert or add to a sub array that was already in the DB
Here is my issue, every day we take a look at the itunes top 100 and we insert the songs and artist into our collection, well infact we use two collections to do this job
but the one I am having issue with is the one that we store every single song and artist that has ever appeared in the iTunes top 100.
see code below
$collection = static::db()->itunes_collection_australia;
$document = $collection->findOne(array('song' => (string)$entry->imname, "artist"=>(string)$entry->imartist));
if (null !== $document) {
$collection->update(
array(array('song' => (string)$entry->imname, "artist"=>(string)$entry->imartist)),
array('$push' => array("date" => array('$each'=> array((string)$date)),"chartno"=> array('$each'=> array($a))),
));
}
else
{
$collection->insert(array("song"=>(string)$entry->imname, "artist"=>(string)$entry->imartist,"preview"=>(string)$preview,"cd_cover"=>(string)$cover, "price"=>(string)$price,"date"=>array((string)$date),"chartno"=>array($a)));
}
what should be happening is if the artist and song is found to already be the the collection , it should update. at the moment it is not running anything.
and if it is updating its not doing it right.
You see the "date" field should be showing multiple dates same with the chartno it should also be showing what position it was in the charts on that day.
here is how it should look when first inserted.
{
"_id" : ObjectId("52ea794d6ed348572d000013"),
"song" : "Timber (feat. Ke$ha)",
"artist" : "Pitbull",
"preview" : "http://a1264.phobos.apple.com/us/r1000/030/Music6/v4/48/30/3c/48303ca0-c509-8c15-4d4a-7ebd65c74725/mzaf_5507852070192786345.plus.aac.p.m4a",
"cd_cover" : "http://a1082.phobos.apple.com/us/r30/Music6/v4/64/41/81/644181ba-d236-211d-809e-057f4352d3d8/886444273480.170x170-75.jpg",
"price" : "$2.19",
"date" : [
"2014-01-29T07:10:38-07:00"
],
"chartno" : [
20
]
}
when the script sees it is back in the top 100 it should add it to the date and chartno fields.
like so
{
"_id" : ObjectId("52ea794d6ed348572d000013"),
"song" : "Timber (feat. Ke$ha)",
"artist" : "Pitbull",
"preview" : "http://a1264.phobos.apple.com/us/r1000/030/Music6/v4/48/30/3c/48303ca0-c509-8c15-4d4a-7ebd65c74725/mzaf_5507852070192786345.plus.aac.p.m4a",
"cd_cover" : "http://a1082.phobos.apple.com/us/r30/Music6/v4/64/41/81/644181ba-d236-211d-809e-057f4352d3d8/886444273480.170x170-75.jpg",
"price" : "$2.19",
"date" : [{
"2014-01-30T07:10:38-07:00"
},{2014-01-31T07:10:38-07:00}],
"chartno" : [
{20},{30}
]
}
however that is not happening infact nothing seems to be getting added.
I am wondering if I have done something wrong? Well clearly I have.
I have also tried the following '$addToSet' but with no success.

your update statement is wrong. you have too many arrays on first parameter. try this:
$collection->update(
array('song' => (string)$entry->imname, "artist"=>(string)$entry->imartist),
array('$push' => array("date" => array('$each'=> array((string)$date)),"chartno"=> array('$each'=> array($a))),
));

Related

Displaying all aggregated results from Elasticsearch query in PHP

I have a field called "arrivalDate" and this field is a string. Each document has an arrivalDate in string format (ex: 20110128). I want my output to be something like this (date and the number of records that have that date):
Date : how many records have that date
20110105 : 5 records
20120501 : 2 records
20120602 : 15 records
I already have the query to get these results.
I am trying to display aggregated results in PHP from Elasticsearch. I want my output to be something like this:
Date : how many records have that date
20110105 : 5 records
20120501 : 2 records
20120602 : 15 records
This is what I have so far:
$json = '{"aggs": { "group_by_date": { "terms": { "field": "arrivalDate" } } } }';
$params = [
'index' => 'pickups',
'type' => 'external',
'body' => $json
];
$results = $es->search($params);
However, I don't know how to display the results in PHP. For example, if I wanted to display the total number of documents I would do echo $results['hits']['total'] How could I display all the dates with the number of records they have in PHP?
I'd suggest using aggregations in the same way you construct the query, from my experience it seems to work quicker. Please see the below code:
'aggs' => [
'group_by_date' => [
'terms' => [
'field' => 'arrivalDate',
'size' => 500
]
]
]
Following that, instead of using the typical results['hits']['hits'] you would switch out the hits parts to results['aggregations']. Then access the returning data by accessing the buckets in the response.
For accessing the data from the aggregation shown above, it would likely be something along the lines of:
foreach ($results as $result){
foreach($result['buckets'] as $record){
echo($record['key']);
}
}
There will be a better way of accessing the array within the array, however, the above loop system works well for me. If you have any issues with accessing the data, let me know.

How to insert an array to mongodb using php?

update(array("loc1"=>$locations[0]),array('$set'=>(object)array("Users"=>(array("user_id"=>$user_id,"user_name"=>$Email)))));
I wrote the above code to insert user_id to the array users, after execution i got the result in mongodb shown below
{
"_id" : ObjectId("5702cfd2c693b54008000035"),
"loc1" : "Anapara",
"loc2" : "Puthucurichy",
"loc3" : "Kadinamkulam",
"loc4" : "Kerala",
"loc5" : "India",
"Users" : {
"user_id" : ObjectId("5702cfd2c693b54008000034"),
"user_name" : "chunks#yahoo.com"
}
}
Here the keyword Users is not becoming an array, i mean i want it in this format (value of user in a square bracket):
"Users" :[ {
"user_id" : ObjectId("5702cfd2c693b54008000034"),
"user_name" : "chunks#yahoo.com"}
]
What modification should i do in my php code to put the values in square bracket?
BSON array ([ ... ]) can be saved from PHP if you use an array indexed by consecutive numbers (a list). So your code needs to be (I'll allow myself to make it more readable to illustrate better):
update(
array("loc1" => $locations[0]),
array('$set' => array(
"Users"=> array( // this makes Users a list
array("user_id"=>$user_id,"user_name"=>$Email) // this is your embedded object
// here could go another embedded object separated by a comma
)
))
);

How to find a mongodb collection entry by ObjectId in php

I have a mongodb database which contains two connected collections.
The first one has a dataset which looks like this:
{
"_id": ObjectId("5326d2a61db62d7d2f8c13c0"),
"reporttype": "visits",
"country": "AT",
"channel": "wifi",
"_level": NumberInt(3)
}
The ObjectId is connected to several datasets in the second collection which look like this:
{
"_id": ObjectId("54c905662d0a99627efe17a9"),
"avg": NumberInt(0),
"chunk_begin": ISODate("2015-01-28T12:00:00.0Z"),
"count": NumberInt(15),
"max": NumberInt(0),
"min": NumberInt(0),
"sum": NumberInt(0),
"tag": ObjectId("5326d2a61db62d7d2f8c13c0")
}
As you can see it the "_id" from the first dataset the same as the "tag" from the second.
I want to write a routine in php which gets the ids from the first collection and finds by them datasets in a certain timeframe in the second collection for deletion.
I get the id from the first collection ok, but I suspect I use it wrongly in the the query for the second collection because nothing is ever found or deleted.
Code looks like this:
// select a collection (analog to a relational database's table)
$tagCollection = $db->tags;
$orderCollection = $db->orders;
// formulate AND query
$aTagCriteria = array(
'reporttype' => new MongoRegex('/[a-z]+/'),
);
// retrieve only _id keys
$fields = array('_id');
$cursor = $tagCollection->find($aTagCriteria, $fields);
$startOfTimeperiod = new MongoDate(strtotime('2015-01-05 00:00:00'));
$endOfTimeperiod = new MongoDate(strtotime('2015-01-07 13:20:00'));
// iterate through the result set
foreach ($cursor as $obj) {
echo '_id: '.$obj['_id'].' | ';
// Until here all is ok, I get the _id as output.
$aOrdercriteria = array(
'tag' => new MongoId($obj['_id']),
'date' => array(
'$lte' => $endOfTimeperiod,
'$gte' => $startOfTimeperiod
),
);
$iCount = $orderCollection->count($aOrdercriteria);
if ($iCount > 0) {
echo PHP_EOL.$iCount.' document(s) found.'.PHP_EOL;
$result = $orderCollection->remove($aOrdercriteria);
echo __FUNCTION__.'|'.__LINE__.' | '.json_encode($result).PHP_EOL;
echo 'Removed document with ID: '.$aOrdercriteria['tag'].PHP_EOL;
}
}
What is the correct way for the search condition so it looks for tag Objects
with the previously found id?
PS:
I tried
'tag' => $obj['_id'],
instead of
'tag' => new MongoId($obj['_id']),
which didn't work either.
So two things had to be changed.
The first one was like EmptyArsenal hinted:
tag' => new MongoId($obj['_id']),
is wrong since $obj['_id'] is already an object.
So
'tag' => $obj['_id'],
is correct.
And if I change my condition from "date" to "chunk_begin" yahooo.... it works. Stupid me.

Update a couple of values in nested array MongoDB

I would like to update a couple of elements in they match given values:
Example : I have a collection with this structure:
{
"_id" : ObjectId("52936a0270c68c04063f0300"),
"channel" : "1",
"content" : "145548",
"keywordsValues" : [
[ObjectId("52816d3370c68c2c1c4b0500"), ObjectId("52816d3370c68c2c1c9f0500")],
[ObjectId("52816d3370c68c2c1c510500"), ObjectId("52816d3370c68c2c1c890500")],
[ObjectId("52816d3370c68c2c1c550500"), ObjectId("52816d3370c68c2c1c850500")],
[ObjectId("52816d3370c68c2c1c6b0500"), ObjectId("52816d3370c68c2c1c990500")]
]
}
And I need to update "keywordsValues" field (just one of the couple in the array [])
Something for example update the 2nd element in keywordsValues:
If we found [firstId,secondId] in keywordsValues field then update the second secondId
$database->Measurements->update(
array('keywordsValues'=>
array(new MongoId(52816d3370c68c2c1c4b0500),new MongoId(52816d3370c68c2c1c9f0500)',$atomic'=>'true')),
array('$set'=>array('keywordsValue.$'=>new MongoId($idNewValue))));
But this doesn't work...
try
array('$set'=>array('keywordsValue'=>new MongoId($idNewValue))));
instead of
array('$set'=>array('keywordsValue.$'=>new MongoId($idNewValue))));
i hope it help to you!

Get top 5 documents with newest nested objects

I have the following data structure in MongoDB:
{ "_id" : ObjectId( "xy" ),
"litter" : [
{ "puppy_name" : "Tom",
"birth_timestamp" : 1353963728 },
{ "puppy_name" : "Ann",
"birth_timestamp" : 1353963997 }
]
}
I have many of these "litter" documents with varying number of puppies. The highter the timestamp number, the younger the puppy is (=born later).
What I would like to do is to retrieve the five youngest puppies from the collection accross all litter documents.
I tried something along
find().sort('litter.birth_timestamp' : -1).limit(5)
to get the the five litters which have the youngest puppies and then to extract the youngest puppy from each litter in the PHP script.
But I am not sure if this will work properly. Any idea on how to do this right (without changing the data structure)?
You can use the new Aggregation Framework in MongoDB 2.2 to achieve this:
<?php
$m = new Mongo();
$collection = $m->selectDB("test")->selectCollection("puppies");
$pipeline = array(
// Create a document stream (one per puppy)
array('$unwind' => '$litter'),
// Sort by birthdate descending
array('$sort' => array (
'litter.birth_timestamp' => -1
)),
// Limit to 5 results
array('$limit' => 5)
);
$results = $collection->aggregate($pipeline);
var_dump($results);
?>

Categories