unwind just if embedded exist - php

I have highly nested mongodb set of objects, so my collection is:
{
"_id":17846384es,
"company_name":"company1",
"company_location":"city1",
"phone":"xxxxx",
"open_time":"xxx",
"products":[
{
"product_id":"123785",
"product_name":"product1",
"user_votes":[
{
"user_id":1,
"vote":1
},
{
"user_id":2,
"vote":2
}
]
},
{
"product_id":"98765",
"product_name":"product2",
"user_votes":[
{
"user_id":5,
"vote":3
},
{
"user_id":3,
"vote":3
}
]
}
]
}
I used some operation like sort and sum on this sub of documents so i used
db.products.aggregate([
{ $unwind: "$products" },
{ $project: {
company_name: 1,
products: {
product_id: 1,
product_name: 1,
user_votes: 1,
votes: { $sum: "$products.user_votes.vote" }
}
} },
{ $sort: { totalVotes: -1 } },
{
$group: {
_id: "$_id",
company_name: { $first: "$company_name" },
products: { $push: "$products" }
}
}
])
to get this result :
{
"_id":17846384es,
"company_name":"company1",
"products":[
{
"product_id":"98765",
"product_name":"product2",
"user_votes":[
{
"user_id":5,
"vote":3
},
{
"user_id":3,
"vote":3
}
]
"votes":6
},
{
"product_id":"123785",
"product_name":"product1",
"user_votes":[
{
"user_id":1,
"vote":1
},
{
"user_id":2,
"vote":2
}
],
"votes":3
}
]
}
but if product document dosen't exist I have an empty result. I want to get a result with company information even if product document doesn't exist.

Firstly, you can use "preserveNullAndEmptyArrays" to preserve the company which doesn't have product array.
The below query should output the company names even if it doesn't have products array.
I think you are trying to sum the votes and sort the product array to get the highest number of products as first element in the array. The below query should produce the result.
db.product.aggregate([
{ $unwind: { path : "$products", preserveNullAndEmptyArrays : true }},
{ $project: {
company_name: 1,
products : { $ifNull : ["$products", "0"]}}
},
{ $project: {
company_name: 1,
products: {
product_id: 1,
product_name: 1,
user_votes: 1,
votes: { $sum: "$products.user_votes.vote" }
}
} },
{ $sort: { "products.votes": -1 } },
{
$group: {
_id: "$_id",
company_name: { $first: "$company_name" },
products: { $push: "$products" }
}
},
]);
In case if you want to keep the companies which doesn't have product at the end. You can add this additional sort as the last pipeline in the above query.
{ $sort: { "products.votes": -1 } },
Output of companies which doesn't have product array would like as below:-
{
"_id" : ObjectId("57f2bd50dd4752c20947fd03"),
"company_name" : "company2",
"products" : [
{
"votes" : 0
}
]
}

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

JSON data should not have key value in numeric and result not coming as per expected result

I am creating JSON with nested set model using recursion. My result is not coming as expected, as this JSON helps me to generate a tree. The brackets are not coming as in required JSON.
i am trying to create a json like this http://fperucic.github.io/treant-js/examples/evolution-tree/example6.js . i am interested in nodeStructure: { }
Issue:
every children has { } but required [ ]
Not required numeric keys
json keys should not come in quotes like "text", "children, "name" , its should come witout quotes
Online compiler: https://3v4l.org/UsXPv
<?php
$category = '{"9":{"id":"9","btc_mlm_user_id":"0","lft":"1","rht":"16","lvl":"0","name":"Root","created":"2017-06-27 05:56:11","modified":"2017-06-27 05:56:11","first_name":"","last_name":"","username":""},"42":{"id":"42","btc_mlm_user_id":"25","lft":"2","rht":"13","lvl":"1","name":"naresh","created":"2017-11-02 10:22:24","modified":"2017-11-02 10:22:24","first_name":"","last_name":"","username":"naresh"},"44":{"id":"44","btc_mlm_user_id":"27","lft":"3","rht":"4","lvl":"2","name":"rahul1","created":"2017-11-02 10:25:53","modified":"2017-11-02 10:25:53","first_name":"","last_name":"","username":"rahul1"},"45":{"id":"45","btc_mlm_user_id":"28","lft":"5","rht":"6","lvl":"2","name":"rahul123","created":"2017-11-02 10:27:19","modified":"2017-11-02 10:27:19","first_name":"","last_name":"","username":"rahul123"},"46":{"id":"46","btc_mlm_user_id":"29","lft":"7","rht":"12","lvl":"2","name":"kapil1","created":"2017-11-02 10:28:20","modified":"2017-11-02 10:28:20","first_name":"","last_name":"","username":"kapil1"},"47":{"id":"47","btc_mlm_user_id":"30","lft":"8","rht":"11","lvl":"3","name":"priya12","created":"2017-11-02 10:30:30","modified":"2017-11-02 10:30:30","first_name":"","last_name":"","username":"priya12"},"48":{"id":"48","btc_mlm_user_id":"31","lft":"9","rht":"10","lvl":"4","name":"amit12","created":"2017-11-02 10:32:00","modified":"2017-11-02 10:32:00","first_name":"","last_name":"","username":"amit12"},"43":{"id":"43","btc_mlm_user_id":"26","lft":"14","rht":"15","lvl":"1","name":"roshan","created":"2017-11-02 10:24:27","modified":"2017-11-02 10:24:27","first_name":"","last_name":"","username":"roshan"}}';
function tree($data, $left = 0, $right = null)
{
$tree = array();
foreach ($data as $key => $value)
{
if ($value['lft'] == $left + 1 && (is_null($right) || $value['rht'] < $right))
{
$tree[$key]['text'] = ['name' => $value['name']];
$tree[$key]['children'] = tree($data, $value['lft'], $value['rht']);
$left = $value['rht'];
}
}
return $tree;
}
$tree = tree(json_decode($category, true));
echo json_encode($tree);
Output:
{
"9": {
"text": {
"name": "Root"
},
"children": {
"42": {
"text": {
"name": "naresh"
},
"children": {
"44": {
"text": {
"name": "rahul1"
},
"children": []
},
"45": {
"text": {
"name": "rahul123"
},
"children": []
},
"46": {
"text": {
"name": "kapil1"
},
"children": {
"47": {
"text": {
"name": "priya12"
},
"children": {
"48": {
"text": {
"name": "amit12"
},
"children": []
}
}
}
}
}
}
},
"43": {
"text": {
"name": "roshan"
},
"children": []
}
}
}
}
Required output:
{
text: {
name: "Root"
},
children: [{
text: {
name: "naresh"
},
children: [{
text: {
name: "rahul1"
},
children: [
[]
],
text: {
name: "rahul123"
},
children: [
[]
],
text: {
name: "kapil1"
},
children: [{
text: {
name: "priya12"
},
children: [{
text: {
name: "amit12"
},
children: [
[]
]
}]
}]
}],
text: {
name: "roshan"
},
children: [
[]
]
}]
}
Here is my MySql records which are i am fetching here to show you in $category json in start.
If you want to get the output you linked, rather than the one in your question (which is invalid as pointed by #RoryMcCrossan, because it contains multiple equal keys per object), then you can change your code to this:
function tree($data, $left = 0, $right = null) {
$tree = array();
foreach ($data as $key => $value) {
if ($value['lft'] == $left + 1 && (is_null($right) || $value['rht'] < $right)) {
$child = []; // Let's make a new child
$child['text'] = ['name' => $value['name']]; // The text is required
$childTree = tree($data, $value['lft'], $value['rht']); // Let's find its children
if (!empty($childTree)) { // If it has children
$child['children'] = $childTree; // Let's save the children
}
$tree[] = $child; // Put the child in the tree
$left = $value['rht'];
}
}
return $tree;
}
$tree = tree(json_decode($category, true))[0]; // Since there's only one root, you want the first element of the tree
Here's the full code: https://3v4l.org/AYCGt
That just leaves you with one problem, according to you, the keys shouldn't have quotes around them. Although I don't really know your motives and it should work with the quotes in Javascript, you could do some replacements using preg_replace, like this:
echo preg_replace('/"(\w+)":/','$1:',json_encode($tree));
This would be the complete code: https://3v4l.org/ZaXip

Elasticsearch - Distinct Values, Not Counts

I am trying to do something similar to this SQL query:
SELECT * FROM table WHERE fileContent LIKE '%keyword%' AND company_id = '1' GROUP BY email
Having read posts similar to this I have this:
{
"query": {
"bool": {
"must": [{
"match": {
"fileContent": {
"query": "keyword"
}
}
}],
"filter": [{
"terms": {
"company_id": [1]
}
}]
}
},
"aggs": {
"group_by_email": {
"terms": {
"field": "email",
"size": 1000
}
}
},
"size": 0
}
Field mappings are:
{
"cvs" : {
"mappings" : {
"application" : {
"_meta" : {
"model" : "Acme\\AppBundle\\Entity\\Application"
},
"dynamic_date_formats" : [ ],
"properties" : {
"email" : {
"type" : "keyword"
},
"fileContent" : {
"type" : "text"
},
"company_id" : {
"type" : "text"
}
}
}
}
}
}
... which are generated from Symfony config.yml:
fos_elastica:
clients:
default:
host: "%elastica.host%"
port: "%elastica.port%"
indexes:
cvs:
client: default
types:
application:
properties:
fileContent: ~
email:
index: not_analyzed
company_id: ~
persistence:
driver: orm
model: Acme\AppBundle\Entity\Application
provider: ~
finder: ~
The filter works fine, but I am finding that hits:hits returns no items (or all results matching the search if I remove size:0) and aggregations:group_by_email:buckets has a count of the groups but not the records themselves. The records that were grouped aren't returned and it's these that I need.
I have also tried with FOSElasticBundle using the query builder if this is your preferred flavour (this works but doesn't have the grouping/aggregation):
$boolQuery = new \Elastica\Query\BoolQuery();
$filterKeywords = new \Elastica\Query\Match();
$filterKeywords->setFieldQuery('fileContent', 'keyword');
$boolQuery->addMust($filterKeywords);
$filterUser = new \Elastica\Query\Terms();
$filterUser->setTerms('company_id', array('1'));
$boolQuery->addFilter($filterUser);
$finder = $this->get('fos_elastica.finder.cvs.application');
Thanks.
For this you need top_hits aggregation inside the terms one you are already using:
"aggs": {
"group_by_email": {
"terms": {
"field": "email",
"size": 1000
},
"aggs": {
"sample_docs": {
"top_hits": {
"size": 100
}
}
}
}
}
top_hits:{size:1} appears to be what I need, having played around with Andrei's answer. This will return one record for each bucket in the aggregation
"aggs": {
"group_by_email": {
"terms": {
"field": "email",
"size": 1000
},
"aggs": {
"sample_docs": {
"top_hits": {
"size": 1
}
}
}
}
}
Ref: top_hits
top_hits helped me too. I had some trouble too, but eventually figured out how to resolve it. So here is my solution:
{
"query": {
"nested": {
"path": "placedOrders",
"query": {
"bool": {
"must": [
{
"term": {
"placedOrders.ownerId": "0a9fdef0-4508-4f9c-aa8c-b3984e39ad1e"
}
}
]
}
}
}
},
"aggs": {
"custom_name1": {
"nested": {
"path": "placedOrders"
},
"aggs": {
"custom_name2": {
"terms": {
"field": "placedOrders.propertyId"
},
"aggs": {
"custom_name3": {
"top_hits": {
"size": 1,
"sort": [
{
"placedOrders.propertyId": {
"order": "desc"
}
}
]
}
}
}
}
}
}
}
}

MongoDB $unwind more than one field and sort by timestamp

I have created one query in that query in that query I am using $unwind more than one field. Query response is fine but my senior suggest me this is wrong query. Because query response is not in proper format and not in ascending order of r_y_b_phasetimestamp timestamp. I given query as follows:
db.energy.aggregate([
{
$project: { EventTS: 1, RPhaseVoltage: 1, YPhaseVoltage:1, BPhaseVoltage:1}
},
{
$unwind: {
path: "$RPhaseVoltage",
includeArrayIndex: "arrayIndex",
preserveNullAndEmptyArrays: true
}
},
{
$unwind: {
path: "$YPhaseVoltage",
includeArrayIndex: "arrayIndex",
preserveNullAndEmptyArrays: true
}
},
{
$unwind: {
path: "$BPhaseVoltage",
includeArrayIndex: "arrayIndex",
preserveNullAndEmptyArrays: true
}
},
{
$match: {
$and: [
{RPhaseVoltage: {$ne: null}},
{YPhaseVoltage: {$ne: null}},
{BPhaseVoltage: {$ne: null}},
]
}
},
{
$project: {
_id:0,
EventTS:1,
RPhaseVoltage: 1,
YPhaseVoltage: 1,
BPhaseVoltage:1,
r_y_b_phasetimestamp: {
"$add": [
{ "$subtract": ["$EventTS", new Date("1970-01-01")]},
{ "$multiply": [ 60000, "$arrayIndex" ] }
]
}
}
},
{
$project: {
"rvoltage_data":["$r_y_b_phasetimestamp", "$RPhaseVoltage"],
"yvoltage_data":["$r_y_b_phasetimestamp", "$YPhaseVoltage"],
"bvoltage_data":["$r_y_b_phasetimestamp", "$BPhaseVoltage"]
}
},
{
$sort:{
r_y_b_phasetimestamp:-1
}
}
]);
My sample of collection as follows
{
"_id" : ObjectId("57742e0f8d8b8fdf278b45d1"),
"EventTS" : ISODate("2016-06-24T12:30:00.000+0000"),
"RPhaseVoltage" : [
null,
231.81,
231.81,
null,
231.42
],
"YPhaseVoltage" : [
229.95,
229.95,
null,
null,
231.32
],
"BPhaseVoltage" : [
null,
231.44,
231.44,
null,
null
]
}
My graph output link is Graph Plotting Link. This query i am using for graph plotting. Please suggest me my query is wrong and why graph is plotting likw this
you are using $project 2 times. when you use $project, only the projected values are passed to the next part of pipeline. before using sort you are not projecting r_y_b_phasetimestamp. so, r_y_b_phasetimestamp will be undefined when sorting and will result in unsorted results. try passing r_y_b_phasetimestamp:"$r_y_b_phasetimestamp" after "bvoltage_data":["$r_y_b_phasetimestamp", "$BPhaseVoltage"] . so the final code is
db.energy.aggregate([
{
$project: { EventTS: 1, RPhaseVoltage: 1, YPhaseVoltage:1, BPhaseVoltage:1}
},
{
$unwind: {
path: "$RPhaseVoltage",
includeArrayIndex: "arrayIndex",
preserveNullAndEmptyArrays: true
}
},
{
$unwind: {
path: "$YPhaseVoltage",
includeArrayIndex: "arrayIndex",
preserveNullAndEmptyArrays: true
}
},
{
$unwind: {
path: "$BPhaseVoltage",
includeArrayIndex: "arrayIndex",
preserveNullAndEmptyArrays: true
}
},
{
$match: {
$and: [
{RPhaseVoltage: {$ne: null}},
{YPhaseVoltage: {$ne: null}},
{BPhaseVoltage: {$ne: null}},
]
}
},
{
$project: {
_id:0,
EventTS:1,
RPhaseVoltage: 1,
YPhaseVoltage: 1,
BPhaseVoltage:1,
r_y_b_phasetimestamp: {
"$add": [
{ "$subtract": ["$EventTS", new Date("1970-01-01")]},
{ "$multiply": [ 60000, "$arrayIndex" ] }
]
}
}
},
{
$project: {
"rvoltage_data":["$r_y_b_phasetimestamp", "$RPhaseVoltage"],
"yvoltage_data":["$r_y_b_phasetimestamp", "$YPhaseVoltage"],
"bvoltage_data":["$r_y_b_phasetimestamp", "$BPhaseVoltage"],
r_y_b_phasetimestamp:"$r_y_b_phasetimestamp"
}
},
{
$sort:{
r_y_b_phasetimestamp:-1
}
}
]);

Categories