Restler: Internal actions - php

Is there a way to perform REST actions in the middle of executing an action? For example, if I perform GET /index.php/book/1 I might receive the following:
[{
"id" : 1,
"title" : "This is a book.",
"owner_id" : 4
}]
But what I'd like to do is before returning the above object, perform a GET /index.php/user/4 so the end result is:
[{
"id" : 1,
"title" : "This is a book.",
"owner" : {
"id" : 4,
"name" : "John Smith",
"age" : 40
}
}]

There is even simple way of doing this with Restler by internally calling another api method directly instead of wasting one call to the server
class User{
public function get($id, $includeOwner = true){
$result = getUserFromDB($id)
if($includeOwner){
$result['owner'] = $this->get(getOwnerIdFromDB($id),false);
}
}
return $result;
}
HTH

Related

json decode and get value using PHP

I have a JSON string and i want to get the value.
$s='{
"subscriptionId" : "51c04a21d714fb3b37d7d5a7",
"originator" : "localhost",
"contextResponses" : [
{
"contextElement" : {
"attributes" : [
{
"name" : "temperature",
"type" : "centigrade",
"value" : "26.5"
}
],
"type" : "Room",
"isPattern" : "false",
"id" : "Room1"
},
"statusCode" : {
"code" : "200",
"reasonPhrase" : "OK"
}
}
]
}';
Here is the code which I used but it didn't work.
$result = json_decode($s,TRUE); //decode json string
$b=$result ['contextResponses']['contextElement']['value']; //get the value????
echo $b;
ContextResponses contains a numerically indexed array (of only one item) and value property is more deeply nested than what you are trying to reference (it is within attributes array). This would appear to be what you need:
$b = $result['contextResponses'][0]['contextElement']['attributes'][0]['value'];
When reading a JSON-serialiazed data structure like that, you need to make sure and note every opening [ or { as they have significant meaning in regards to how you need to reference the items that follow it. You also may want to consider using something like var_dump($result) in your investigations, as this will show you the structure of the data after it has been deserialized, oftentimes making it easier to understand.
Also, proper indention when looking at something like this would help. Use something like http://jsonlint.com to copy/paste your JSON for easy reformatting. If you had your structure like the following, nesting levels become more readily apparent.
{
"subscriptionId": "51c04a21d714fb3b37d7d5a7",
"originator": "localhost",
"contextResponses": [
{
"contextElement": {
"attributes": [
{
"name": "temperature",
"type": "centigrade",
"value": "26.5"
}
],
"type": "Room",
"isPattern": "false",
"id": "Room1"
},
"statusCode": {
"code": "200",
"reasonPhrase": "OK"
}
}
]
}

MongoDB Map Reduce newbie (PHP)

I'm new to the map reduce concept and even though I'm making some slow progress, I'm finding some issues that I need some help with.
I have a simple collection consisting of an id, city and and destination, something like this:
{ "_id" : "5230e7e00000000000000000", "city" : "Boston", "to" : "Chicago" },
{ "_id" : "523fe7e00000000000000000", "city" : "New York", "to" : "Miami" },
{ "_id" : "5240e1e00000000000000000", "city" : "Boston", "to" : "Miami" },
{ "_id" : "536fe4e00000000000000000", "city" : "Washington D.C.", "to" : "Boston" },
{ "_id" : "53ffe7e00000000000000000", "city" : "New York", "to" : "Boston" },
{ "_id" : "5740e1e00000000000000000", "city" : "Boston", "to" : "Miami" },
...
(Please do note that this data is just made up for example purposes)
I'd like to group by city the destinations including a count:
{ "city" : "Boston", values : [{"Chicago",1}, {"Miami",2}] }
{ "city" : "New York", values : [{"Miami",1}, {"Boston",1}] }
{ "city" : "Washington D.C.", values : [{"Boston", 1}] }
For this I'm starting to playing with this function to map:
function() {
emit(this.city, this.to);
}
which performs the expected grouping. My reduce function is this:
function(key, values) {
var reduced = {"to":[]};
for (var i in values) {
var item = values[i];
reduced.to.push(item);
}
return reduced;
}
which gives somewhat an expected output:
{ "_id" : ObjectId("522f8a9181f01e671a853adb"), "value" : { "to" : [ "Boston", "Miami" ] } }
{ "_id" : ObjectId("522f933a81f01e671a853ade"), "value" : { "to" : [ "Chicago", "Miami", "Miami" ] } }
{ "_id" : ObjectId("5231f0ed81f01e671a853ae0"), "value" : "Boston" }
As you can see, I still haven't counted the repeated cities, but as can be seen above, for some reason the last result in the output doesn't look good. I'd expected it to be
{ "_id" : ObjectId("5231f0ed81f01e671a853ae0"), "value" : { "to" : ["Boston"] } }
Has this anything to do with the fact that there is a single item? Is there any way to obtain this?
Thank you.
I see you are asking about a PHP issue, but you are using javascript to ask, so I’m assuming a javascript answer will help you move things along. As such here is the javascript needed in the shell to run your aggregation. I strong suggest getting your aggregation working in the shell(or some other javascript editor) in general and then translating it into the language of your choice. It is a lot easier to see what is going on and there faster using this method. You can then run:
use admin
db.runCommand( { setParameter: 1, logLevel: 2 } )
to check the bson output of your selected language vs what the shell looks like. This will appear in the terminal if mongo is in the foreground, otherwise you’ll have ot look in the logs.
Summing the routes in the aggregation framework [AF] with Mongo is fairly strait forward. The AF is faster and easier to use then map reduce[MR]. Though in this case they both have similar issues, simply pushing to an array won’t yield a count in and of itself (in MR you either need more logic in your reduce function or to use a finalize function).
With the AF using the example data provided this pipeline is useful:
db.agg1.aggregate([
{$group:{
_id: { city: "$city", to: "$to" },
count: { $sum: 1 }
}},
{$group: {
_id: "$_id.city",
to:{ $push: {to: "$_id.to", count: "$count"}}
}}
]);
The aggregation framework can only operate on known fields, but many pipeline operations so a problem needs to broken down with that as a consideration.
Above, the 1st stage calculates the numbers need, for which there are 3 fixed fields: the source, the destination, and the count.
The second stage has 2 fixed fields, one of which is an array, which is only being pushed to (all the data for the final form is there).
For MR you can do this:
var map = function() {
var key = {source:this.city, dest:this.to};
emit(key, 1);
};
var reduce = function(key, values) {
return Array.sum(values);
};
A separate function will have to pretty it however.
If you have any additional questions please don’t hesitate to ask.
Best,
Charlie

Mongodb nested array search

document structure example is:
{
"dob": "12-13-2001",
"name": "Kam",
"visits": {
"0": {
"service_date": "12-5-2011",
"payment": "40",
"chk_number": "1234455",
},
"1": {
"service_date": "12-15-2011",
"payment": "45",
"chk_number": "3461234",
},
"2": {
"service_date": "12-25-2011",
"payment": "25",
"chk_number": "9821234",
}
}
}
{
"dob": "10-01-1998",
"name": "Sam",
"visits": {
"0": {
"service_date": "12-5-2011",
"payment": "30",
"chk_number": "86786464",
},
"1": {
"service_date": "12-15-2011",
"payment": "35",
"chk_number": "45643461234",
},
"2": {
"service_date": "12-25-2011",
"payment": "20",
"chk_number": "4569821234",
}
}
}
In PHP i want to list all those "visits" information (and corresponding "name" ) for which payment is less than "30".
I want to print only the visits with "payment" < "30" not others. Is such query possible, or do i have to get entire document first using search and then use PHP to select such visits??
In the example document, the "payment" values are given as strings which may not work as intended with the $lt command. For this response, I have converted them to integers.
Wildcard queries are not possible with MongoDB, so with the given document structure, the key (0,1,2, etcetera) of the sub-document must be known. For instance, the following query will work:
> db.test.find({"visits.2.payment":{$lt:35}})
However,
> db.test.find({"visits.payment":{$lt:35}})
Will not work in this case, and
> db.test.find({"visits.*.payment":{$lt:35}})
will also not return any results.
In order to be able to query the embedded "visits" documents, you must change your document structure and make "visits" into an array or embedded documents, like so:
> db.test2.find().pretty()
{
"_id" : ObjectId("4f16199d3563af4cb141c547"),
"dob" : "10-01-1998",
"name" : "Sam",
"visits" : [
{
"service_date" : "12-5-2011",
"payment" : 30,
"chk_number" : "86786464"
},
{
"service_date" : "12-15-2011",
"payment" : 35,
"chk_number" : "45643461234"
},
{
"service_date" : "12-25-2011",
"payment" : 20,
"chk_number" : "4569821234"
}
]
}
Now you can query all of the embedded documents in "visits":
> db.test2.find({"visits.payment":{$lt:35}})
For more information, please refer to the Mongo documentation on dot notation:
http://www.mongodb.org/display/DOCS/Dot+Notation+%28Reaching+into+Objects%29
Now on to the second part of your question: it is not possible to return only a conditional sub-set of embedded documents.
With either document format, it is not possible to return a document containing ONLY the sub-documents that match the query. If one of the sub-documents matches the query , then the entire document matches the query, and it will be returned.
As per the Mongo Document "Retrieving a subset of fields"
http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields
We can return parts of embedded documents like so:
> db.test2.find({"visits.payment":{$lt:35}},{"visits.service_date":1}).pretty()
{
"_id" : ObjectId("4f16199d3563af4cb141c547"),
"visits" : [
{
"service_date" : "12-5-2011"
},
{
"service_date" : "12-15-2011"
},
{
"service_date" : "12-25-2011"
}
]
}
But we cannot have conditional retrieval of some sub documents. The closest that we can get is the $slice operator, but this is not conditional, and you will have to first know the location of each sub-document in the array:
http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields#RetrievingaSubsetofFields-RetrievingaSubrangeofArrayElements
In order for the application to display only the embedded documents that match the query, it will have to be done programmatically.
You may try:
$results = $mongodb->find(array("visits.payment" => array('$lt' => 30)));
But i don't know if it will work since visits is an object. BTW judging from what you posted it could be transfered to array (or should since numerical property names tends to cause confusion)
try - db.test2.find({"visits.payment":"35"})

MongoDB PHP nested documents

ok lets say i have this collection in my tv database
"season" : "1", "episodes" : {"code" : ["1x01", "1x02", "1x03"], "title" : ["Dont Look Back", "Genesis", "Third"]},
"season" : "2", "episodes" : {"code" : ["2x01", "2x02", "2x03"], "title" : ["D2ont Look Back", "G2enesis", "T2hird"]},
"season" : "3", "episodes" : {"code" : ["3x01", "3x02", "3x03"], "title" : ["D3ont Look Back", "G3enesis", "T3hird"]},
"season" : "4", "episodes" : {"code" : ["4x01", "4x02", "4x03"], "title" : ["D4ont Look Back", "G4enesis", "T4hird"]}
how do i make it so that only, lets say the episodes from season 2 are shown?
ive been trying using
echo $obj['episodes']['code'][0];
but it only shows episodes from the last row
im pretty sure my nesting is all wrong but im new to mongo and im having trouble trying to map this out
any advice?
You need to use find() first.
$a = $coll->findOne(array('season' => '2');
That will return an array $a which will have keys 'episodes', 'title'
So once you find the document with findOne, you would then just access the data using $a['title'] or whatever fields you need

MongoDB-PHP: JOIN-like query

Here are the objects:
courses
{ "name" : "Biology", "_id" : ObjectId("4b0552b0f0da7d1eb6f126a1") }
students
{
"name" : "Joe",
"classes" : [
{
"$ref" : "courses",
"$id" : ObjectId("4b0552b0f0da7d1eb6f126a1")
}
],
"_id" : ObjectId("4b0552e4f0da7d1eb6f126a2")
}
Using the PHP Mongo Class, how do I get all the students that has a biology course?
Thanks
You'll need to query twice. I dont have my environment in front of me, but something similar to what's below. I may have the "nested" portion of the second query incorrect.
// First grab the ID for the course.
$course = $collection->findOne(array("name" => "Biology"));
// Next query the students collection.
$collection->find(array("classes" => array("id" => $course['_id'])));

Categories