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"
}
}
]
}
Related
I have a use defined json string inside a database.
The JSON string has lots of levels. I know my user will define a kay called "basevalue" and place it somewhere in the json.
The problem is, I don't know ahead of time where in the JSON it will be placed, and every use is likely to place is in different places in the array, perhaps at different levels.
This is an example of the JSON data being saved by the user:
{
"name": "",
"type": "layout",
"children": [
{
"name": "",
"type": "section",
"children": [
{
"name": "",
"type": "row",
"children": [
{
"name": "",
"type": "column",
"props": {
},
"children": []
},
{
"type": "column",
"children": [
{
"type": "itemdata",
"props": {
**"basevalue": "100",**
},
"children": []
}
]
}
]
}
]
}
I'm converting this data to an array using json_decode:
$json = json_decode($json, true);
No I need to search through the array, and find the key of 'basevalue' and then get whatever value the user has input, in the case above that would be '100'.
So to the issue is, I have no idea what 'node' the 'basevalue' key will be. It could be 40 deep, it could be in the first 'children' node.
This is up to the user.
So how do I take any version of the JSON string about and return the '100'?
Many thanks.
You can recursively iterate over the data and get the value of the key basevalue. To make this search faster, we can adopt an early exit approach similar to breadth first search. By this, we call add all values who are arrays in a queue and continue our search for the key basevalue and later on deal with pending queue. This would be faster than basic recursion because a lot of times it's possible that key was on the same level but we searched all the way down on all other trees which proved out to be trivial.
Snippet:
function getBaseValue($arr,$search_key){
$pending_calls = [];
foreach($arr as $key => $value){
if(is_array($value)){
$pending_calls[] = $value; // queue them for later judgement
}else if($search_key === $key){
return $value;
}
}
foreach($pending_calls as $call){
$returned_val = getBaseValue($call,$search_key);
if($returned_val !== false) return $returned_val;
}
return false;
}
echo getBaseValue($arr,'basevalue');
Demo: https://3v4l.org/gdLK1
I am getting json array after getting applying query logic.
[
{
"id": "3",
"diag_name": "LT Diagnostics",
"test_name": "Alk PO4",
"booking_date": "2018-05-20"
},
{
"id": "3",
"diag_name": "LT Diagnostics",
"test_name": "CRP",
"booking_date": "2018-05-20"
},
{
"id": "4",
"diag_name": "Seepz Diagnostics",
"test_name": "Alk PO4",
"booking_date": "2018-05-21"
}
]
But i want a more justified json array written below.
[
{
"diag_name": "LT Diagnostics",
"test_name": [
{
"id": "3",
"name" : "Alk PO4"
},
{
"id": "3",
"name" : "CRP"
}
],
"booking_date": "2018-05-20"
},
{
"diag_name": "Seepz Diagnostics",
"test_name": [
{
"id": "4",
"name" : "Alk PO4"
}
],
"booking_date": "2018-05-21"
},
]
I am not getting it,How to do in php. I want a more consolidate json format.
Have you tried changing your SQL query to group by diag_name and booking_date? That would be the first step I’d employ to get the outer data.
Formatting the data in the nested manner you’re after could be a function of whatever record serializer you’re using — does it support nested JSON as a return type, or only flat JSON as your example return value shows?
If the record set -> JSON serializer only ever returns flat data, the comments above are correct that you will have to write your own formatter to change the shape of the JSON yourself...
The accepted answer of this other question may be of help:
Create multi-level JSON with PHP and MySQL
I'm not a PHP guy but this is a typical scenario to use functional programming by means of the monad Map.
Looking online I've found this article that could help you.
Changing datasource output is not always (seldom indeed) a viable option.
Enjoy coding
I'm using ElasticSearch's PHP client and I find really difficult to return results with scores whenever I want to search for a word that is "hidden" within a string.
This is an example:
I want to get all the documents where the field "file" has the word "anses" and files are named like this:
axx14anses19122015.zip
What I know about it
I know I should tokenize those words, can't realize how to do it.
Also I've read about aggregations but I'm really new to ES and I have to deliver a working piece ASAP.
What I've tried so far
REGEXP: using regular expressions is very expensive and does not return any scores, which is a must-to-have in order to shrink results and bring the user accurate information.
Wildcards: same thing, slow and no scores
Own script where I have a dictionary and search for critical words using regexp, if match, create a new field within that matched document with the word. The reason is to create a TOKEN so in future searches I can use regular match with scores. Negative side: the dictionary thing was totally denied by my boss so I'm here asking for any ideas.
Thanks in advance.
I suggest in your case nGram tokenizer see the example
I will create a analyzer and a mapping for a doc type
PUT /test_index
{
"settings": {
"number_of_shards": 1,
"analysis": {
"tokenizer": {
"ngram_tokenizer": {
"type": "nGram",
"min_gram": 4,
"max_gram": 4,
"token_chars": [ "letter", "digit" ]
}
},
"analyzer": {
"ngram_tokenizer_analyzer": {
"type": "custom",
"tokenizer": "ngram_tokenizer",
"filter": [
"lowercase"
]
}
}
}
},
"mappings": {
"doc": {
"properties": {
"text_field": {
"type": "string",
"term_vector": "yes",
"analyzer": "ngram_tokenizer_analyzer"
}
}
}
}
}
after that I`ll insert a document using your file name
PUT /test_index/doc/1
{
"text_field": "axx14anses19122015"
}
now I`ll just will use a query match
POST /test_index/_search
{
"query": {
"match": {
"text_field": "anses"
}
}
}
and will receive a reponse like this
{
"took": 8,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.10848885,
"hits": [
{
"_index": "test_index",
"_type": "doc",
"_id": "1",
"_score": 0.10848885,
"_source": {
"text_field": "axx14anses19122015"
}
}
]
}
}
What i did?
i just created a nGram tokenizer that will explode our string in 4 characters terms and will index this terms separated and they will be searched when I search a part of the string.
To see more, read this article https://qbox.io/blog/an-introduction-to-ngrams-in-elasticsearch
Hope it help!
Ok after trying -so- many times it worked. I'll share the solution just in case someone else needs it. Thank you so much to Waldemar, it was a really good approach and I still cannot see why it's not working.
curl -XPUT 'http://ipaddresshere/tokentest' -d
'{ "settings":
{ "number_of_shards": 1, "analysis" :
{ "analyzer" : { "myngram" : { "tokenizer" : "mytokenizer" } },
"tokenizer" : { "mytokenizer" : {
"type" : "nGram",
"min_gram" : "3",
"max_gram" : "5",
"token_chars" : [ "letter", "digit" ] } } } },
"mappings":
{ "doc" :
{ "properties" :
{ "field" : {
"type" : "string",
"term_vector" : "yes",
"analyzer" : "myngram" } } } } }'
Sorry for bad indentation, I'm really hurry but want to post the solution.
So, this will take any string from "field" and split it into nGrams with lenght 3 to 5. For example: "abcanses14f.zip" will result in:
abc, abca, abcan, bca, bcan, bcans, etc... until it reaches anses or a similar term which is matcheable and has a score related to it.
I am trying to create a "nested" array within an object that I am returning from a database.
I can have more than one footnote per "thing".
This is what I am currently getting back:
JSON
{
"data": [{
"id": "123",
"type": "foo",
"color": "bar",
"footnote_id": "1",
"footnote_text": " Footnote one"
}]
}
Here is the result I'm trying to generate:
JSON
{
"data": [{
"id": "123",
"type": "foo",
"color": "bar",
"footnotes": [{
"footnote_id": "1",
"footnote_text": " Footnote one"
},
{
"footnote_id": "2",
"footnote_text": "Footnote two"
}]
}]
}
I have a footnotes table that has all kinds of footnotes (footnote_id and such).
I have a type table that has all kinds of things in it (type_id and such).
I also have a type_footnotes table that only has two columns: type_id and footnote_id
I'm not sure how to create the footnotes property of the response object - then display the results within that array.
Thank you for your time!
EDIT
Here is the query - I thought I had posted this as well. My apologies.
PHP
public function get_thing($type_id) {
$this->db->select('type.type_id, type.type, type.type_color');
$this->db->join('footnotes', 'footnotes.footnote_id, footnotes.footnote_text');
$this->db->join('type_footnotes, type_footnotes.type_id = type.type_id');
$query = $this->db->get_where('type', array('type.type_id' => $type_id), 1);
if ($query->num_rows() > 0) {
return $query->result();
}
}
Remove the limit, and post here what do you get as result :
$query = $this->db->get_where('type', array('type.type_id' => $type_id));
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"})