How to group orders by different cities using Laravel, MySql, JSON - mysql

Trying to build a report result of orders related information of a laravel project. But struggling to find out a solution on a specific data structure.
My Request :
// Date Ranges
$fromDate = $this->request->fromDate;
$toDate = $this->request->toDate;
So the result should be within a date range.
My orders table :
order_id order_addresses grand_total
------------------------------------------
1 JSON DATA 3,000.00
2 JSON DATA 2,000.00
3 JSON DATA 1,500.00
So My JSON DATA looks like this :
{
"delivery_address":{
"House":"Offline House",
"Street":"Offline Road",
"Area":"Offline Area",
"PostCode":"1230",
"City":"City1",
"Country":"Country1",
"ContactPerson":"Offline User",
"ContactNumber":"01XXXXXXXX"
}
}
I just want the response as :
{
"orders": 3, // How many orders are there in that particular city
"totals": "5,500.00", // Total how much the cost of orders in that city
"groupby": "City1",
},
{
"orders": 5,
"totals": "7,500.00",
"groupby": "City2",
},
...,
...
I am seeking a solution using query builder in laravel with MySQL.
This is an existing project so I can't really change the structure how it was built. So, any suggestions on how I can extract the cities from JSON DATA having relation with the orders identity along with the totals and all.
I just need the order_ids I think city wise then I can structure my result anyway I like to achieve end result.
If anything confusion here, please let me know so that I can make it clear.
Thanks in Advance !

I would suggest grouping fetched data using Laravel Collection functions.
Order Model
class Order extends Model {
// This will cast data to native types.
// so order_address json string to array
protected $casts = [
'order_addresses' => 'array',
];
}
Controller function
// Fetch orders from the database as you usually do
// without considering about grouping.
// with your conditions.
// I will simply use all() for example.
$orders = Order::all();
// First group by city
// Then map to get the result you want.
$groupedOrders = $orders->groupBy(function($order) {
// since we added it to the casts array in the model
// laravel will automatically cast json string to an array.
// So now order_address is an array.
return $order->order_addresses['City'];
})
->map(function($groupedOrders, $groupName) {
return [
'orders' => $groupedOrders->count(),
'totals' => $groupedOrders->sum('grand_total'),
'groupby' => $groupName,
];
});

Related

How can I compare 2 columns in the same table but not in the same row with Laravel?

I want to display the values of columns with the same menu_id and the same menu_parentid. However, the array is empty when I execute in Postman. I want the values of columns with common menu_id and menu_parentid displayed in an array.
Controller
public function showMenu()
{
return [
'menus' => Menu::whereColumn('menu_parentid', 'menu_id')
->distinct()
->get()
->map(function ($item) {
return [
'menu_id' => $item->menu_id,
'menu_name' => $item->menu_name,
'menu_icon' => $item->menu_icon,
];
})
];
}
When I test on Postman, I get the following
{
"menus": []
}
Screenshot of database
I think you're going about this the wrong way. Instead of doing a query like that, you can make a relationship of the model with itself to get the $menu->children and then perform the array mapping the way you like. I don't want to write it out and guess how you like it to be displayed, so can you elaborate how you would like the array to be structured? Is it like this?:
"menus": [
[parent_id1, child_id1],
[parent_id1, child_id2],
[parent_id2, child_id3]
];
Or is it a different structure where the parent id's are all mixed with the children? I can only give you hints without you clarifying your structure.
You can you have to select a One to many relation in model.
public function childs()
{
return $this->hasMany(Menu::class, 'menu_parentid', 'menu_id');
}
Then, you can select items with this query,
Menu::with('childs')->distinct()->get();

Trying to get filtered response from query with multiple terms from elasticsearch

As the title states, im trying to make a query that doesnt return the entire document, but only certain fields, but with multiple exact terms.
Im using Guzzle from laravel to contruct my query:
$response = $client->post('cvr-permanent/_search', [
'auth' => ['USERNAME', 'PASSWORD'],
'json' => [
"_source" => ["Vrvirksomhed.attributter", "Vrvirksomhed.deltagerRelation.organisationer.medlemsData.attributter"],
"query" => [
"bool"=> [
"must"=> [
[
"term"=> [
"Vrvirksomhed.cvrNummer" => $vat
]
]],
"must_not"=> [ ],
"should"=> [ ]
]
],
"from"=> 0,
"size"=> 10,
"sort"=> [ ]
]
]);
I want the data from the Vrvirksomhed.cvrNummer and the data i want is where Vrvirksomhed.attributter.type => "KAPITAL" and Vrvirksomhed.deltagerRelation.deltager.navne and where Vrvirksomhed.deltagerRelation.organisation.attributter.type = "EJERANDEL_PROCENT"
Im very confused about how to make this query work because it is multiple terms but not really. Also very new to elasticsearch.
I tried the "terms" but couldnt really get it to work.
The query i have made above, return way too much data i dont need, and not all the data i DO need.
Hope you can help
**EDIT
Something like this maybe, but translated to elasticsearch
SELECT attributter.type": "KAPITAL" AND deltagerRelation.deltager.navne AND deltagerRelation.organisation.attributter.type": "EJERANDEL_PROCENT FROM Vrvirksomhed WHERE cvrNummer = $vat
***EDIT
Hopefully more clarification:
Okay, sorry ill try to make it clearer. The object i want is a company with a certain vat number. So Vrvirksomhed.cvrNummer is that, and that has to be the term. It returns a gigantic object with so many arrays in arrays. I do not want all of this data but only some of it. The data i need from this big object, is the object in the array Vrvirksomhed.attributter that has the type : "KAPITAL field, and not all of the attributter. Then i want Vrvirksomhed.deltagerRelation.deltager.navne which i can get by just putting it in the _source because i want all of these objects. But then i want Vrvirksomhed. deltagerRelation.organisation.attributter that again is a bunch of objects in the array attributter but i only want the ones with the type : "EJERANDEL_PROCENT
So i can´t really add them as additional "terms" because the only real term is the "cvrNummer", everything else is just filtering the response. I tried with filters etc, but to no avail
Heres a pastebin so you can see the clusterfuck i am dealing with. THis is what i have been able to sort it to so far, with putting the things in _source but without the extra "filtering" of "KAPITAL" and "EJERANDEL_PROCENT"
https://pastebin.com/b8hWWz1R
You want to get only documents which match several conditions, and you need only a subset of fields from those documents, correct?
In SQL (taking some liberties with the field names and structure), your query would be something like:
SELECT cvrNummer
FROM Vrvirksomhed
WHERE attributter_type = 'KAPITAL'
AND deltagerRelation_deltager_navne = 'you left this out in your question'
AND deltagerRelation_organisation_attributter_type = 'EJERANDEL_PROCENT'
As explained in the Elasticsearch Guide†, the equivalent to this in Elasticsearch is a query with a bool clause that contains all your conditions, and a _source parameter which says what fields you want to get back in the response. Something like the following:
{
"_source": ["cvrNummer"]
"query": {
"bool": {
"must": [
{ "term": "attributter.type": "KAPITAL" },
{ "term": "deltagerRelation.deltager.navne": "you left this out in your question" },
{ "term": "deltagerRelation.organisation.attributter.type": "EJERANDEL_PROCENT" }
]
}
}
}
† Do note that the syntax in this guide is for Elasticsearch 2.x. The current version is 7.x, and many things have changed since then!
See https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html for how to construct a bool query using the new syntax;
see https://www.elastic.co/guide/en/elasticsearch/reference/current/term-level-queries.html for how to use the term-level queries, which you probably want;
also see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html and consider using filter context, since you probably don't care about the score of your query.

Sailsjs MVC map params from external API to multiple models

I need to create a database of shopify orders so I can run advanced queries and sales reports that you can't do in the shopify admin area. I'm building in Sails .12 and mysql. Shopify lets you register a webhook so that every time an order is placed, it creates a POST to the specified URL with the order data in the body as JSON. The products ordered are an array of JSON objects as one of the values in the POST:
{
"id": 123456,
"email": "jon#doe.ca",
"created_at": "2017-01-10T14:26:25-05:00",
...//many more entires
"line_items": [
{
"id": 24361829895,
"variant_id": 12345,
"title": "T-Shirt",
"quantity": 1,
"price": "140.00",
},
{
"id": 44361829895,
"variant_id": 42345,
"title": "Hat",
"quantity": 1,
"price": "40.00",
},
]
}
I need to save the order into an Orders table, and the products ordered into a line_items table that is a one to many relation; one order can have many line_items (products ordered). There are over 100 key-value pairs sent by the webhook, and I'm saving all of it. I've created my two models where I define the data type, so now i have very long Order.js and Line_item.js files, and I'm using the
line_items: {
collection: 'line_item',
via: 'order_id'
},
in my Order.js, and
order_id: {
model: 'order'
},
in my Line_item.js models to relate them. Is this the correct way to denfine my two tables? Also, where would I put the code that maps the JSON to the model parameters? If I put that code in the controllers, would I have to type another 100+ lines of code to map each json value to its correct parameter. The how would I save to the two different models/tables? Eg:
var newOrder = {};
newOrder.id =req.param('id');
newOrder.email = req.param('email');
newOrder.name = req.param('name');
...//over 100 lines more, then Order.create(newOrder, ...)
var newLine_items = req.params('line_items'); //an array
_.forEach(newLine_items, function(line_item){
var newLine_item = {};
newLine_item.id = line_item.id;
newLine_item.order_id = newOrder.id;
newLine_item.title = line_item.title;
//etc for over 20 more lines, then Line_item.create(newLine_item, ...)
});
I need to save the order into an Orders table, and the products ordered into a line_items table that is a one to many relation; one order can have many line_items (products ordered).
That sounds completely reasonable, well, besides the use of the Oxford comma :)
There are over 100 key-value pairs sent by the webhook
I'm not sure that I understand exactly what this is or what it is used for within this process.
That being said, it might help to have a single attribute in your model for this which has a JSON value, then retrieve and work with it as JSON instead of trying to manually account for each attribute if that is what you're doing over there?
It really depends on your use case and how you'll use the data though but I figure if the format changes you might have a problem, not so if it's just being stored and parsed as a JSON object?
Also, where would I put the code that maps the JSON to the model parameters
In v0.12.x take a look at Services.
In v1, Services will still work but moving this logic into Helpers might be a good option but then, it seems that a custom model method would be a better one.
Here is a shorter version of your code:
var newOrder = req.allParams();
newLine_items = {};
_.forEach(newOrder.line_items, function(line_item) {
newLine_items.push(line_item);
});
Here is what your logic might look like:
var newOrder = req.allParams();
// Store the order
Order
.create(newOrders)
.exec(function (err, result) {
if (err) // handle the error
var newLine_items = {};
_.forEach(newOrder.line_items, function(line_item) {
// Add the order id for association
line_item.order_id = result.id;
// Add the new line item with the orders id
newLine_items.push(line_item);
});
// Store the orders line items
LineItems
.create(newLine_items)
.exec(function (err, result) {
if (err) // handle the error
// Handle success
});
});
And the lifecycle callback in the Order model:
beforeCreate: function (values, cb) {
delete(values.line_items);
cb();
}
But you really should look into bluebird promises as the model methods in version one of sails have opt in support for them and it helps to negate the pyramid of doom that is starting in my example and is also something that you want to avoid :P

Make a join query in loopback.io

I am trying to build a simple application using loopback.io as process of my learning. I have set up the project, created models and apis are working fine.
Now I am trying to create a custom api which can get the data from two different models by making a join query. So i have a two models
stories : id, title, noteId
notes : id , desc
i have stories.js file as
module.exports = function(Stories) {
Stories.list = function(cb) {
// make a join query
};
Stories.remoteMethod(
'list', {
http: {
path: '/list',
verb: 'get'
},
returns: {
arg: 'list',
type: 'array'
}
}
);
};
In general i will make a join in php api but here i am bit confused.Can i pass a raw query to database here or does loopback has some different way of achieving this. Any help would be appreciated.
You don't need to pass sql query. You can query data using PersistedModel find method by using include filter
In order to use include filter you have to create model relation.
For example:
Note relation:
"relations": {
"stories": {
"type": "hasMany",
"model": "Story",
"foreignKey": "noteId"
}
},
Query:
Note.find({include: ['stories']}, function(err, data) { ... });

Sequelize include (how to structure query)?

I have a query I'm trying to perform based on a one to many relationship.
As an example there is a model called Users and one called Projects.
Users hasMany Projects
Projects have many types which are stored in a type (enum) column. There are 4 different types that potentially a user may have that I want to load. The catch is I want to include the most recent project record (createdAt column) for all networks that potentially will be there. I have not found a way to structure the query for it to work as an include. I have however found a way to do a raw query which does what I want.
I am looking for a way without having to do a raw query. By doing the raw query I have to map the returned results to users I've returned from the other method, or I have to do a simple include and then trim off all the results that are not the most recent. The latter is fine, but I see this getting slower as a user will have many projects and it will keep growing steadily.
This allow serialize a json for anywhere action about a model. Read it, very well
sequelize-virtual-fields
// define models
var Person = sequelize.define('Person', { name: Sequelize.STRING });
var Task = sequelize.define('Task', {
name: Sequelize.STRING,
nameWithPerson: {
type: Sequelize.VIRTUAL,
get: function() { return this.name + ' (' + this.Person.name + ')' }
attributes: [ 'name' ],
include: [ { model: Person, attributes: [ 'name' ] } ],
order: [ ['name'], [ Person, 'name' ] ]
}
});
// define associations
Task.belongsTo(Person);
Person.hasMany(Task);
// activate virtual fields functionality
sequelize.initVirtualFields();