Shifting specific index's in array to front based on value inside - php

I have the following array.
{
"flow":[
{
"tasks":[
{ "id":"1", "uid":"bryan" },
{ "id":"2", "uid":"eric" }
]
},
{
"tasks":[
{ "id":"1", "uid":"bryan" },
{ "id":"2", "uid":"eric" }
]
},
{
"tasks":[
{ "id":"1", "uid":"bryan" },
{ "id":"2", "uid":"eric" }
]
},
{
"tasks":[
{ "id":"1", "uid":"bryan" },
{ "id":"2", "uid":"eric" },
{ "id":"3", "uid":"eric" },
{ "id":"4", "uid":"bryan" }
]
}
]
}
Let's say I am eric. If I am eric, I am trying to move all items with the uid of eric to the front of the tasks array.
So that the array would end looking like this:
{
"flow":[
{
"tasks":[
{ "id":"2", "uid":"eric" },
{ "id":"1", "uid":"bryan" }
]
},
{
"tasks":[
{ "id":"2", "uid":"eric" },
{ "id":"1", "uid":"bryan" }
]
},
{
"tasks":[
{ "id":"2", "uid":"eric" },
{ "id":"1", "uid":"bryan" }
]
},
{
"tasks":[
{ "id":"2", "uid":"eric" },
{ "id":"3", "uid":"eric" },
{ "id":"1", "uid":"bryan" },
{ "id":"4", "uid":"bryan" }
]
}
]
}
I've attempted to make a function to do it, but for some reason it's not working the way I intended it to. Does anyone know what I'm doing wrong?
function reorder_flow($flow, $uid)
{
foreach($flow as &$step)
{
//step is the array with tasks
$tasks = $step['tasks'];
$new_tasks = array();
foreach($tasks as $key => $t)
{
if($t['uid'] == $uid)
{
$new_tasks = $new_tasks + $t;
unset($tasks[$key]);
}
}
$step['tasks'] = $new_tasks + $step['tasks'];
}
return $flow;
}

This is a traversal/sorting problem.
$json = <<<JSON
{
"flow":[
{
"tasks":[
{ "id":"1", "uid":"bryan" },
{ "id":"2", "uid":"eric" }
]
},
{
"tasks":[
{ "id":"1", "uid":"bryan" },
{ "id":"2", "uid":"eric" }
]
},
{
"tasks":[
{ "id":"1", "uid":"bryan" },
{ "id":"2", "uid":"eric" }
]
},
{
"tasks":[
{ "id":"1", "uid":"bryan" },
{ "id":"2", "uid":"eric" },
{ "id":"3", "uid":"eric" },
{ "id":"4", "uid":"bryan" }
]
}
]
}
JSON;
$flow = json_decode($json, true);
array_walk($flow['flow'], function(&$flowItem, $key){
usort($flowItem['tasks'], function($a, $b){
$aIsMatch = $a['uid'] === 'eric';
$bIsMatch = $b['uid'] === 'eric';
if ($aIsMatch && $bIsMatch) {
return 0;
}
if ($aIsMatch) {
return -1;
}
if ($bIsMatch) {
return 1;
}
// Fallback sorting criteria - you could use something else or just return 0
return strcasecmp($a['uid'], $b['uid']);
});
});
echo json_encode($flow, JSON_PRETTY_PRINT);

Please try this:
function sortByUID(&$array, $uid) {
array_walk ($array, function($obj) use($uid) {
uasort($obj->tasks, function($a, $b) use($uid) {
return $a->uid == $uid ? -1 : 1;
});
});
}
sortByUID($data->flow, 'eric');
Demo: https://3v4l.org/mOhDX
I hope this will help.

notes:
+ does not work with arrays in that way
json_decode should have the second parameter set to true to get nested arrays
then try this in the foreach:
//step is the array with tasks
$new_tasks=array();
foreach($step['tasks'] as $t){
if($t['uid'] == $uid){
array_unshift($new_tasks,$t);
} else {
array_push($new_tasks,$t);
}
}
$step['tasks'] = $new_tasks;

Related

Getting values from meta_data

I have a problem with getting some values from Woocommerce $item object.
I'm trying to extract data from "meta_data" -> "_advanced_woo_discount_item_total_discount" -> initial_price, discounted_price and "discount_value" from "total _discount_details".
I tried with $item->get_meta_data(); but got a blank return.
{
"id":55,
"order_id":11501,
"name":"test",
"product_id":6419,
"variation_id":6421,
"quantity":1,
"tax_class":"",
"subtotal":"182.491803",
"subtotal_tax":"40.15",
"total":"182.491803",
"total_tax":"40.15",
"taxes":{
"total":{"1":"40.148197"},
"subtotal":{"1":"40.148197"}
},
"meta_data":[{
"id":457,
"key":"pa_velikost",
"value":"180cm"
},
{
"id":458,
"key":"_advanced_woo_discount_item_total_discount",
"value":
{
"initial_price":278.3,
"discounted_price":222.64000000000001,
"total_discount_details":
{
"8e39099d383d7d50a8c4fce98e59cc79":
{
"1":
{
"set_discount":0,
"bulk_discount":0,
"simple_discount":
{
"discount_type":"percentage",
"discount_value":"20",
"discount_quantity":1,
"discount_price_per_quantity":55.660000000000004,
"discount_price":55.660000000000004
}
}
}
},
"cart_discount_details":[],
"apply_as_cart_rule":["no"],
"discount_lines":
{
"non_applied":{
"quantity":0,
"discount":0,
"price":278.3,
"calculate_discount_from":278.3
},
"0":
{
"quantity":1,
"discount":55.660000000000004,
"original_price":278.3,
"discounted_price":222.64000000000001
}
},
"cart_quantity":1,
"product_id":6421,
"initial_price_based_on_tax_settings":278.3,
"discounted_price_based_on_tax_settings":222.64000000000001
}
}
]
}
Try with get_meta()
Example:
$item->get_meta('_advanced_woo_discount_item_total_discount')

How to make dynamic elastic search query based on my given input values in Elastic Search

I have written elastic search query in static values, now i want to make as a dynamic like i have input fields, based on the input values i have to make my dynamic elastic search query. how can i do it? any one please update my answer.
INPUT
{
"userID" : "USER1",
"groupID" : "5b278f8856db693c457b4697",
"contentType " : "question",
"contentID" : "5",
"contentFlow": [
{
"contentId": "123",
"contentType": "topic"
},
{
"contentId": "456",
"contentType": "concept"
},
{
"contentId": "100",
"contentType": "sdl"
}
]
}
STATIC QUERY
{
"size":999,
"query":{
"bool":{
"must":[
{
"term":{
"userId":"USER1"
}
},
{
"term":{
"contentId":"5"
}
},
{
"bool":{
"must":[
{
"term":{
"contentPath.contentType":"topic"
}
},
{
"term":{
"contentPath.contentId":"123"
}
}
]
}
},
{
"bool":{
"must":[
{
"term":{
"contentPath.contentType":"concept"
}
},
{
"term":{
"contentPath.contentId":"456"
}
}
]
}
},
{
"bool":{
"must":[
{
"term":{
"contentPath.contentType":"sdl"
}
},
{
"term":{
"contentPath.contentId":"100"
}
}
]
}
}
]
}
}
}
I am new to learning elastic search, kindly help me out on this problem

elasticsearch-php multiple range query not working

I am using a client for elasticsearch client for elasticsearch, i am not getting the right result for a multiple range query.
The body that i use for querying:
{
"index":"locations",
"type":"portugal",
"body":{
"aggs":{
"unique":{
"aggs":{
"documents":{
"top_hits":{
"size":50
}
}
},
"terms":{
"field":"cp3"
}
}
},
"query":{
"filtered":{
"filter":{
"bool":{
"must":{
"range":{
"latitude":{
"gte":41.1373667,
"lte":41.1373767
},
"longitude":{
"gte":-8.631723,
"lte":-8.631713
}
}
}
}
}
}
}
}
}
the result:
{
"took":2,
"timed_out":false,
"_shards":{
"total":5,
"successful":5,
"failed":0
},
"hits":{
"total":1,
"max_score":1,
"hits":[
{
"_index":"locations",
"_type":"portugal",
"_id":"AVTJ4I0g_vwSgXBDKO-W",
"_score":1,
"_source":{
"id":222956,
"latitude":41.0383217,
"longitude":-8.6317147
}
}
]
},
"aggregations":{
"unique":{
"doc_count_error_upper_bound":0,
"sum_other_doc_count":0,
"buckets":[
{
"key":199,
"doc_count":1,
"documents":{
"hits":{
"total":1,
"max_score":1,
"hits":[
{
"_index":"locations",
"_type":"portugal",
"_id":"AVTJ4I0g_vwSgXBDKO-W",
"_score":1,
"_source":{
"id":222956,
"latitude":41.0383217,
"longitude":-8.6317147
}
}
]
}
}
}
]
}
}
}
as you can see the result's latitude is not inside the latitude range i gave it.
Using the Head plugin from elasticsearch to test:
my query:
{
"query":{
"bool":{
"must":[
{
"range":{
"latitude":{
"gte":"41.1363671",
"lte":"41.1363771"
}
}
},
{
"range":{
"longitude":{
"gt":"-8.6318828",
"lte":"-8.6318728"
}
}
}
],
"must_not":[
],
"should":[
]
}
},
"from":0,
"size":10,
"sort":[
],
"aggs":{
}
}
The result:
(empty), there is no records in this range.
Edit:
added the mapping for my index:
{
"locations":{
"aliases":{
},
"mappings":{
"portugal":{
"properties":{
"cp3":{
"type":"long"
},
"cp4":{
"type":"long"
},
"cpalf":{
"type":"string"
},
"id":{
"type":"long"
},
"latitude":{
"type":"double"
},
"localidade":{
"type":"string"
},
"longitude":{
"type":"double"
}
}
}
},
"settings":{
"index":{
"creation_date":"1463675755006",
"number_of_shards":"5",
"number_of_replicas":"1",
"uuid":"C9OO0ig_QyeigqSufK8_dA",
"version":{
"created":"2030199"
}
}
},
"warmers":{
}
}
}
Test with the following query :
{
"query":{
"bool":{
"must":[
{
"range":{
"latitude":{
"gte": 41.1363671,
"lte": 41.1363771
}
}
},
{
"range":{
"longitude":{
"gt": -8.6318828,
"lte": -8.6318728
}
}
}
],
"must_not":[
],
"should":[
]
}
},
"from":0,
"size":10,
"sort":[
],
"aggs":{
}
}
As longitude and latitude fields are double type the should be compare with double, but you have compared with string.

Same aggregation on multiple metrics Elasticsearch

I have setup snowplow with Elasticsearch.
When I want to get the data out I just do normal queries and use aggregates to get them by day, country etc.
So I want to figure out clickthru rate for these aggregations, I have 2 kind of events: page views and clicks.
Currently I do 2 queries:
Page Views:
{
"size": 0,
"query": {
"filtered": {
"filter": {
"bool": {
"must": [
{
"term": {
"event": "page_view"
}
}
],
"must_not": {
"term": {
"br_family": "Robot"
}
}
}
}
}
},
"aggs": {
"dates": {
"date_histogram": {
"field": "collector_tstamp",
"interval": "day"
}
}
}
}
Clicks:
{
"size": 0,
"query": {
"filtered": {
"filter": {
"bool": {
"must": [
{
"term": {
"event": "struct"
}
},
{
"term": {
"se_action": "click"
}
}
],
"must_not": {
"term": {
"br_family": "Robot"
}
}
}
}
}
},
"aggs": {
"dates": {
"date_histogram": {
"field": "collector_tstamp",
"interval": "day"
}
}
}
}
I format the response to something easier to use and then merge them in PHP using something like this.
function merge_metrics($pv,$c){
$r = array();
if(count($pv) > 0){
foreach ($pv as $key => $value) {
$r[$value['name']]['page_views'] += $value['count'];
}
}
if(count($c) > 0){
foreach ($c as $key => $value) {
$r[$value['name']]['clicks'] += $value['count'];
}
}
$rf = array();
foreach ($r as $key => $value) {
$tmp_clicks = isset($value['clicks']) ? $value['clicks'] : 0;
$tmp_page_views = isset($value['page_views']) ? isset($value['page_views']) : 0;
$rf[] = array(
'name' => $key,
'page_views' => $tmp_page_views,
'clicks' => $tmp_clicks,
'ctr' => ctr($tmp_clicks,$tmp_page_views)
);
}
return $rf;
}
Both $pv and $c are arrays that contain the aggregates that result from querying Elasticsearch and I do some formatting for ease of use.
My question is:
Is it possible get multiple metrics(in my case page views and clicks, these are specific filters) and perform same aggregations on both ? then returning the aggregations something like :
{
"data": [
{
"day": "2015-10-13",
"page_views": 61,
"clicks": 0,
},
{
"day": "2015-10-14",
"page_views": 135,
"clicks": 1,
},
{
"day": "2015-10-15",
"page_views": 39,
"clicks": 0,
}
]
}
But without me having to manually merge them ?
Yes, it is definitely possible if you merge your aggregations into one single query. For instance, I suppose you have one query like this for page views:
{
"query": {...}
"aggregations": {
"by_day": {
"date_histogram": {
"field": "day",
"interval": "day"
},
"aggs": {
"page_views_per_day": {
"sum": {
"field": "page_views"
}
}
}
}
}
}
And another query like this for clicks:
{
"query": {...}
"aggregations": {
"by_day": {
"date_histogram": {
"field": "day",
"interval": "day"
},
"aggs": {
"clicks_per_day": {
"sum": {
"field": "clicks"
}
}
}
}
}
}
Provided you have the same constraints in your query, you can definitely merge them together at the date_histogram level, like this:
{
"query": {...}
"aggregations": {
"by_day": {
"date_histogram": {
"field": "day",
"interval": "day"
},
"aggs": {
"page_views_per_day": {
"sum": {
"field": "page_views"
}
},
"clicks_per_day": {
"sum": {
"field": "clicks"
}
}
}
}
}
}
UPDATE
Since your queries are different for each of your aggregations, we need to do it slightly differently, i.e. by using an additional filters aggregation, like this:
{
"size": 0,
"query": {
"filtered": {
"filter": {
"bool": {
"must": [
{
"terms": {
"event": [
"page_view",
"struct"
]
}
}
],
"should": {
"term": {
"se_action": "click"
}
},
"must_not": {
"term": {
"br_family": "Robot"
}
}
}
}
}
},
"aggs": {
"dates": {
"date_histogram": {
"field": "collector_tstamp",
"interval": "day"
},
"aggs": {
"my_filters": {
"filters": {
"filters": {
"page_views_filter": {
"bool": {
"must": [
{
"term": {
"event": "page_view"
}
}
],
"must_not": {
"term": {
"br_family": "Robot"
}
}
}
},
"clicks_filter": {
"bool": {
"must": [
{
"term": {
"event": "struct"
}
},
{
"term": {
"se_action": "click"
}
}
],
"must_not": {
"term": {
"br_family": "Robot"
}
}
}
}
}
}
}
}
}
}
}
Now for each daily bucket, you're going to end up with two sub-buckets, one for the count of page views and another for the count of clicks.

I think it is in the number of arrays in the array and not all of them have data. [duplicate]

This question already has an answer here:
How to extract and access data from JSON with PHP?
(1 answer)
Closed 7 years ago.
Any help? This has been driving me nuts!!! I have taken an xml file and dumped the namespaces and have a great array but for the life of me can't figure out how to work with the json to get variable for:
{
"ListMatchingProductsResponse": {
"ListMatchingProductsResult": {
"Products": {
"Product": [
{
"Identifiers": {
"MarketplaceASIN": {
"MarketplaceId": "ATVPDKIKX0DER",
"ASIN": "B000WTLJIQ"
}
},
"AttributeSets": [],
"Relationships": {
"VariationParent": {
"Identifiers": {
"MarketplaceASIN": {
"MarketplaceId": "ATVPDKIKX0DER",
"ASIN": "**B00FM1EXEQ**"
}
}
}
},
"SalesRankings": {
"SalesRank": [
{
"ProductCategoryId": "pet_products_display_on_website",
"Rank": "115236"
},
{
"ProductCategoryId": "**5769007011**",
"Rank": "362"
}
]
}
},
{
"Identifiers": {
"MarketplaceASIN": {
"MarketplaceId": "ATVPDKIKX0DER",
"ASIN": "B00NDY7666"
}
},
"AttributeSets": [],
"Relationships": [],
"SalesRankings": []
},
{
"Identifiers": {
"MarketplaceASIN": {
"MarketplaceId": "ATVPDKIKX0DER",
"ASIN": "B009YJ3JSI"
}
},
"AttributeSets": [],
"Relationships": {
"VariationParent": {
"Identifiers": {
"MarketplaceASIN": {
"MarketplaceId": "ATVPDKIKX0DER",
"ASIN": "B00P3MYXHQ"
}
}
}
},
"SalesRankings": {
"SalesRank": [
{
"ProductCategoryId": "pet_products_display_on_website",
"Rank": "180220"
},
{
"ProductCategoryId": "3203999011",
"Rank": "8108"
}
]
}
},
{
"Identifiers": {
"MarketplaceASIN": {
"MarketplaceId": "ATVPDKIKX0DER",
"ASIN": "B00ARCFLFA"
}
},
"AttributeSets": [],
"Relationships": [],
"SalesRankings": {
"SalesRank": [
{
"ProductCategoryId": "pet_products_display_on_website",
"Rank": "297848"
},
{
"ProductCategoryId": "5769009011",
"Rank": "879"
}
]
}
},
{
"Identifiers": {
"MarketplaceASIN": {
"MarketplaceId": "ATVPDKIKX0DER",
"ASIN": "B00DJAEX6U"
}
},
"AttributeSets": [],
"Relationships": {
"VariationParent": {
"Identifiers": {
"MarketplaceASIN": {
"MarketplaceId": "ATVPDKIKX0DER",
"ASIN": "B0091TK10K"
}
}
}
},
"SalesRankings": []
},
{
"Identifiers": {
"MarketplaceASIN": {
"MarketplaceId": "ATVPDKIKX0DER",
"ASIN": "B00FC7ALY6"
}
},
"AttributeSets": [],
"Relationships": [],
"SalesRankings": []
}
]
}
},
"ResponseMetadata": {
"RequestId": "9d9da767-ffc5-4eb3-ab95-8f9e91dc7af2"
}
}
}
use json_decode() and it will turn your json into an object.
$json = json_decode(<json_string));
Use json_decode() to return an array then use foreach loop
$result = json_decode($yourJSON);
foreach($result as $key => $val){
//do something here
echo 'Key: ' .$key . ' Value: ' . $val;
}

Categories