Json layout grails respond - json

Currently i'm using a custom marshaller to render json:
JSON.registerObjectMarshaller( PlannedEvent) { PlannedEvent pe ->
return [
id : pe.id,
event : [
eventId : pe.baseEvent.id,
subject : pe.baseEvent.subject
],
//rooms: pe.rooms
rooms: [
id : pe.rooms
]
]
}
This gives the following output:
{"id":1,"event":{"eventId":626,"subject":"Baggeren hc (Kv2)"},"rooms":{"id":[8]}}
I would like to know how to set up my map so the value for rooms is a list with each index representing a separate room. Instead of keys, like "id", being set up as a list. The solution in comment gives to much information about the room, so I can't use that.
Wanted result :
"rooms":[{"id":8},{"id":9}]}

If i am correct for your domain modelling you have a hasMany relationship between PlannedEvent & Room .So if you want to get only the list of ROOMS as IDs from the PlannedEvent domian you need to register custom marshallar for Rooms also like :
JSON.registerObjectMarshaller( Room) { Room room ->
// Map of IDs is returned from here
def returnMap = [:]
returnMap["id"] = room.id
return returnMap
}
And in PlannedEvent:
JSON.registerObjectMarshaller( PlannedEvent) { PlannedEvent pe ->
// This is also a map but the value of key rooms will contain the list of IDs of each room
def roomList = [:]
roomList["rooms"] = pe.rooms
return roomList
}
And for next time please clarify your domians & also what do you want clearly.

Related

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

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,
];
});

Sequelize - Where clause in a nested 'include' statement does return results correctly in Node

I have 5 db tables:
Template, Capability, Deployment, Level, Requirement
Template (PK) -> has many Capability (FK)
Capability (PK) -> has many Deployments (FK) && Capability has many Levels (FK)
Level (PK) -> has many Requirement (FK)
I want to retrieve all templates, with the related foreign keys all the way down to the Requirements.
However, I would like to limit the number of Levels to just the ones that are not deleted (isDeleted : false).
This works if there is DATA retrieved, BUT if there are no records returned from the Levels tables based on the Where (isDeleted), Sequelize will return an empty array for the Deployments table as well. This query correct data if records are found from the Levels table. However, shouldn't the records from the deployment table be returned regardless since it is a different table?
Template.hasMany(Capability, { foreignKey : {name : 'templateId'} })
Capability.hasMany(Deployment, { foreignKey : {name : 'capabilityId'} });
Capability.hasMany(Level, {foreignKey : {name : 'capabilityId'} });
Level.hasMany(Requirement, {foreignKey : {name : 'levelId'}});
const allModules =
await Template.findAll({
include : [ {
model: Capability,
as: 'capabilities',
include : [
{
model: Deployment,
as : 'deployments'
},{
model: Level,
as : 'levels',
where : { isDeleted : false }, // this is the failing part ( if no records are returned both the Deployment recordset and the Level recordset fail)
include : [{
model : Requirement,
as : 'requirements',
}],
},]
}],
})
You might be asking for something impossible. You said:
Capability.hasMany(Level, ...
Level.hasMany(Requirement ....
If there is no Level (or, if the level is marked as deleted), the link between Capability and Requirement is broken, so those Requirements cannot be retrieved. Under what capability would they appear?
OTOH, If you're looking for other outer join situations, try required : false. For example, you could add this to your query to retrieve Capabilities that have no deployments as follows:
...
include : [ {
model: Capability,
as: 'capabilities',
include : [
{
model: Deployment,
as : 'deployments',
required : false // outer join
}
...

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

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();

Play Scala Anorm One to Many relationship

Coming from play anorm, create a model from json without passing anorm PK value in the json I'm trying to add Seq[Address] to case class like
case class User(
id: Pk[Long] = NotAssigned,
name: String = "",
email: String = "",
addresses: Seq[Address])
Address is a simple object/class with three Strings. An user can have more than 1 address, how do I get all the addresses along with the User in findAll.
def findAll(): Seq[User] = {
Logger.info("select * from pt_users")
DB.withConnection { implicit connection =>
SQL(
"""
select * from pt_users where name like {query} limit {size} offset {offset}
""").as(User.list *)
}
}
A side note about something I have found useful: if you're not sure you will always want to fetch the addresses for a user, you can avoid adding that relation as a field and instead use tuples or other data structures for representing them. This would allow you to have a method like this:
def allUsersWithAddresses(): Map[User, Seq[Address])] = ...
But still have methods that return only users without having the joined data.
To read a join (or subselect) you will have to parse the combined output with a parser, something like this:
.as(User ~ Address *).groupBy(_._1)
If you really want to put the addresses inside of user, you'd have to make the address list empty from the user parser and then map each distinct user into one with the addresses:
.as(User ~ Address *).groupBy(_._1).map {
case (user, addresses) => user.copy(addresses = addresses)
}
Note, the examples are just pointers to an approximate solution, not copy-paste-and-compile ready code.
Hope it helped!
This will work
/** Parses a `Blog` paired with an optional `Post` that can be later be collapsed into one object. */
val parser: RowParser[(Blog, Option[Post])] = {
simple ~ Post.parser.? map {
case blog~post => (blog, post)
}
}
def list: List[Blog] = {
DB.withConnection { implicit c =>
SQL("""
SELECT * FROM blogs b
LEFT OUTER JOIN posts p ON(p.blog_id = b.id)
""").as(parser *)
.groupBy(_._1)
.mapValues(_.map(_._2).flatten)
.toList
.map{ case (blog, posts) => blog.copy(posts = posts) }
}
}
Copied from https://index.scala-lang.org/mhzajac/anorm-relational/anorm-relational/0.3.0?target=_2.12