Deserialize JSON with nested categories - mysql

My Controller Class:
public function postAction(Request $request)
{
$content = $request->getContent();
$category = $this->get('jms_serializer')->deserialize($content,'AppBundle\Entity\Category','json');
$errors = $this->get('validator')->validate($category);
if (count($errors) > 0) {
return new View("NAME LENGTH MUST BE >4",Response::HTTP_BAD_REQUEST);
} else {
$em = $this->getDoctrine()->getManager();
$em->persist($category);
$em->flush();
return new View($category, Response::HTTP_OK);
}
}
Entity:
class Category
{
private $id;
private $parent;
public function getChildren()
{
return $this->children;
}
private $children;
public function __construct()
{
$this->children = new ArrayCollection();
}
//setters and getters
Doctrine.yml:
AppBundle\Entity\Category:
type: entity
oneToMany:
children:
targetEntity: AppBundle\Entity\Category
mappedBy: parent
orderBy:
name: ASC
manyToOne:
parent:
targetEntity: AppBundle\Entity\Category
inversedBy: children
joinColumn:
name: parentId
referencedColumn: id
table: category
repositoryClass: AppBundle\Repository\CategoryRepository
id:
id:
column: id
type: integer
id: true
generator:
strategy: AUTO
fields:
name:
type: string
lenght: 255
When I send POST json request like this:
{
"name": "Child to 8",
"parentId": "8"
}
In MySQL table i do not recieve parentId:
mysql> select * from category;
+----+--------------------+----------+
| id | name | parentId |
+----+--------------------+----------+
| 1 | Primary Category | NULL |
| 2 | Secondary Category | 1 |
| 3 | D_child | 1 |
| 4 | F_child | 1 |
| 5 | Z_child | 1 |
| 6 | Y_child | 1 |
| 7 | H_child | 1 |
| 8 | A_child | 1 |
| 9 | Child to 8 | NULL |<----- must be 8
+----+--------------------+----------+
But after deserialization i receive this:
{
"id": 9,
"name": "Child to 8"
}
I understand that id is an integer, but parentId is already an object of class Category. But how to make it so that he also signed up?
How can i do this? Maybe I do not understand something ...

You need to have a .yml config file for serializer. In your case - Entity.Category.yml.
In this file add property of nested entities, set him a type of you Entity and for be sure accessors (setter, getter).

Related

Laravel nested relations eager load respect ancestor id

Let's say I have a model called Research. Each research belongsToMany Location models. And each Location model BelongsToMany Contact models. BUT, each Contact is also related to Research.
class Research extends Model {
protected $table = 'researches';
public function locations()
{
return BelongsToMany( Location::class, 'research_locations_list', 'research_id', 'location_id' );
}
}
class Location extends Model {
protected $table = 'locations';
public function researches()
{
return BelongsToMany( Research::class, 'research_locations_list', 'research_id', 'location_id' );
}
public function contacts()
{
return BelongsToMany( Contact::class, 'location_contacts_list', 'location_id', 'contact_id' );
}
}
class Contact extends Model {
protected $table = 'contacts';
public function locations()
{
return BelongsToMany( Location::class, 'location_contacts_list', 'location_id', 'contact_id' );
}
}
researches table:
+----+------------+
| id | research |
+----+------------+
| 1 | Research 1 |
| 2 | Research 2 |
+----+------------+
locations table:
+----+---------------+
| id | location |
+----+---------------+
| 1 | United States |
| 2 | Great Britain |
| 3 | Germany |
+----+---------------+
contacts table:
+----+---------+
| id | contact |
+----+---------+
| 1 | Jack |
| 2 | John |
| 3 | Hanz |
+----+---------+
research_locations_list table:
+----+-------------+-------------+
| id | research_id | location_id |
+----+-------------+-------------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 2 |
| 4 | 2 | 3 |
+----+-------------+-------------+
So Research 1 is being conducted in United States and Great Britain, Research 2 in Great Britain and Germany
location_contacts_list table:
+----+-------------+------------+-------------+
| id | location_id | contact_id | research_id |
+----+-------------+------------+-------------+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 2 | 1 |
| 3 | 2 | 1 | 2 |
| 4 | 3 | 3 | 2 |
+----+-------------+------------+-------------+
Research 1 should have Jack and John as contacts in United States and no contacts elsewhere;
Research 2 should have John as contact in Great Britain and Hanz in Germany;
Now, with lazy load I can achieve that:
$researches = Research::all();
foreach( $researches as $research )
{
foreach( $research->locations as $location )
{
$contacts = $location->contacts()->wherePivot( 'research_id', $research->id )->get();
// Will return John and Jack in United States for Research 1 and John in Great Britain and Hanz in Germany for Research 2
}
}
Now, the question is: how do I achieve this with eager loading?
$researches = Research::with( 'locations.contacts' )->all();
foreach( $researches as $research )
{
foreach( $research->locations as $location )
{
$contacts = $location->contacts;
// Will return John and Jack in United States, John in Great Britain ( which is not supposed to happen ) for Research 1 and John in Great Britain and Hanz in Germany for Research 2
}
}
Perhaps I can instruct somehow for contacts to respect ancestor id? Like:
$research = Research::with( 'locations.contacts' )->where( 'researches.id = location_contacts_list.research_id' )->all();
UPDATE
The closest I came up to solving this is modifying the Location model like this:
class Location extends Model {
protected $table = 'locations';
public function researches()
{
return BelongsToMany( Research::class, 'research_locations_list', 'research_id', 'location_id' );
}
public function contacts()
{
return BelongsToMany( Contact::class, 'location_contacts_list', 'location_id', 'contact_id' );
}
// Modify contacts attribute getter
public function getContactsAttribute()
{
$contacts = $this->contacts();
if( !empty( $this->pivot->research_id ) )
{
$contacts = $contacts->wherePivot( 'research_id', $this->pivot->research_id );
}
return $contacts->get();
}
}
But it looks kind of dirty...
In your solution you get N+1 query problem. I can suggest the following solution:
class Research extends Model
{
protected $table = 'researches';
public function locations(): BelongsToMany
{
return $this->belongsToMany(Location::class, 'research_locations_list');
}
public function contacts(): BelongsToMany
{
return $this->belongsToMany(Contact::class, 'location_contacts_list')
->withPivot('location_id');
}
public function contactsByLocationAttribute(int $locationId): Collection
{
return $this->contacts
->filter(static function ($contact) use ($locationId) {
return $contact->pivot->location_id === $locationId;
});
}
}
$researches = Research::with(['locations', 'contacts'])->get();
foreach ($researches as $research) {
foreach ($research->locations as $location) {
$contacts = $research->contactsByLocation($location->id);
}
}
here there will always be only 3 queries to the database. And only necessary models will be loaded
If I got it right, you want to add some conditions inside your with statement. If you want to use eloquent syntax, you can do it like this:
$research = Research::with(['YOUR RELATION' => function ($query) {
$query->where('YOUR COLUMN', 'EQUALS TO SOMETHING');
}])->get();
Keep in mind that since inside with you use nested relationships, like locations.contacts, the where function inside the query, will filter only the last model (in this case that would be contacts). If you want to filter both locations and contacts based on some conditions, you have to write something similar to this (just an example):
$research = Research::with(['locations' => function ($query) {
$query->where('id', 1)->with(['contacts' => function ($query) {
$query->where('name', 'Tim');
}]);
})->get();
In order to do that though, you need to create a relationship also with your pivot table (if you want to use it also inside the conditions). Otherwise, you have to use a different syntax, using joins. Check this page from docs for query builders https://laravel.com/docs/9.x/queries#main-content
Perhaps, this https://laravel.com/docs/9.x/eloquent-relationships#has-many-through helps you. You should try to this

Grails, MySQL and extended classes

Here is my abstract class :
package mypackage.commons
abstract class Content {
String name
static constraints = {
name nullable: false, blank: false, size: 1..50
}
}
Here is my class which is extended :
package mypackage.project
import mypackage.commons.Content
class Plane extends Content {
String something;
}
Here is my Bootstrap.groovy file :
package mypackage
import mypackage.commons.Content
import mypackage.project.Plane
class BootStrap {
def init = { servletContext ->
Plane boing1 = new Plane (name: 'Boing', something: 'Hello').save()
Plane boing2 = new Plane (name: 'Boing', something: 'Goodbye').save()
}
def destroy = {
}
}
The problem is when I go on MySQL, when I use SHOW TABLES, I only can see content plane.
Here is the content of SELECT * FROM content;
+----+---------+-------+-------------------------+-----------+
| id | version | name | class | something |
+----+---------+-------+-------------------------+-----------+
| 1 | 0 | Boing | mypackage.project.Plane | Hello |
| 2 | 0 | Boing | mypackage.project.Plane | Goodbye |
+----+---------+-------+-------------------------+-----------+
EDIT
After testing Mike's answer :
package mypackage.commons
abstract class Content {
String name
static constraints = {
name nullable: false, blank: false, size: 1..50
}
static mapping = {
tablePerHierarchy false
}
}
here is the result of SHOW TABLES
+-----------------------+
| Tables_in_my_database |
+-----------------------+
| content |
| plane |
+-----------------------+
Here is the result of SELECT * FROM content :
+----+---------+-------+
| id | version | name |
+----+---------+-------+
| 1 | 0 | Boing |
| 2 | 0 | Boing |
+----+---------+-------+
Here is the result of SELECT * FROM plane :
+----+------------+
| id | something |
+----+------------+
| 1 | Hello |
| 2 | Goodbye |
+----+------------+
END OF EDIT
Expected behaviour :
SHOW TABLES; should show me only the table plane
SELECT * FROM plane should show me this :
+----+---------+-------+------------+
| id | version | name | something |
+----+---------+-------+------------+
| 1 | 0 | Boing | Hello |
| 2 | 0 | Boing | Goodbye |
+----+---------+-------+------------+
How can I obtain the expected result ?
Is it possible ?
Thanks in advance.
You need to tell Grails to use table-per-subclass strategy by telling it not to use table-per-hierarchy like:
package mypackage.commons
abstract class Content {
String name
static constraints = {
name nullable: false, blank: false, size: 1..50
}
static mapping = {
tablePerHierarchy false
}
}
I found an answer, I wonder if it's the best way, but it works.
This topic helps me : https://github.com/grails/grails-data-mapping/issues/1254
Firstly, I understand that if I don't want a class to be mapped by Grails, I have to put this class outside of "Domain" package.
So I moove my Content class into src -> main -> groovy -> common (I created this folder) -> Content.groovy
Here is my Content class :
package common
abstract class Content {
String name
static constraints = {
name nullable: false, blank: false, size: 1..50
}
}
Here is my Plane class :
package mypackage.project
import common.Content
class Plane extends Content {
String something;
}
And here is my Bootstrap.groovy :
package mypackage
import mypackage.project.Plane
class BootStrap {
def init = { servletContext ->
Plane boing1 = new Plane (name: 'Boing', something: 'Hello').save()
Plane boing2 = new Plane (name: 'Boing', something: 'Goodbye').save()
}
def destroy = {
}
}
So I avoid tablePerHierarchy use.
In the topic, thay talked about #MappedSupperclass, I don't know what it refers to. I did not use it.
Expected behaviour is reach.
Is it the correct way to do it ?

How to make nested JSON response in Go?

I am new in Go and need some help.
In my PostgreSQL database I have 4 table. They called: surveys, questions, options and surveys_questions_options.
They looks like this:
surveys table:
| survey_id (uuid4) | survey_name (varchar) |
|--------------------------------------|-----------------------|
| 0cf1cf18-d5fd-474e-a8be-754fbdc89720 | April |
| b9fg55d9-n5fy-s7fe-s5bh-856fbdc89720 | May |
questions table:
| question_id (int) | question_text (text) |
|-------------------|------------------------------|
| 1 | What is your favorite color? |
options table:
| option_id (int) | option_text (text) |
|-------------------|--------------------|
| 1 | red |
| 2 | blue |
| 3 | grey |
| 4 | green |
| 5 | brown |
surveys_questions_options table combines data from all three previous tables:
| survey_id | question_id | option_id |
|--------------------------------------|-------------|-----------|
| 0cf1cf18-d5fd-474e-a8be-754fbdc89720 | 1 | 1 |
| 0cf1cf18-d5fd-474e-a8be-754fbdc89720 | 1 | 2 |
| 0cf1cf18-d5fd-474e-a8be-754fbdc89720 | 1 | 3 |
| b9fg55d9-n5fy-s7fe-s5bh-856fbdc89720 | 1 | 3 |
| b9fg55d9-n5fy-s7fe-s5bh-856fbdc89720 | 1 | 4 |
| b9fg55d9-n5fy-s7fe-s5bh-856fbdc89720 | 1 | 5 |
How can I make nested JSON response in Go? I use GORM library. I want a JSON response like this:
[
{
"survey_id": "0cf1cf18-d5fd-474e-a8be-754fbdc89720",
"survey_name": "April",
"questions": [
{
"question_id": 1,
"question_text": "What is your favorite color?",
"options": [
{
"option_id": 1,
"option_text": "red"
},
{
"option_id": 2,
"option_text": "blue"
},
{
"option_id": 3,
"option_text": "grey"
},
]
}
]
},
{
"survey_id": "b9fg55d9-n5fy-s7fe-s5bh-856fbdc89720",
"survey_name": "May",
"questions": [
{
"question_id": 1,
"question_text": "What is your favorite color?",
"options": [
{
"option_id": 3,
"option_text": "grey"
},
{
"option_id": 4,
"option_text": "green"
},
{
"option_id": 5,
"option_text": "brown"
},
]
}
]
}
]
My models looks like this:
type Survey struct {
SurveyID string `gorm:"primary_key" json:"survey_id"`
SurveyName string `gorm:"not null" json:"survey_name"`
Questions []Question
}
type Question struct {
QuestionID int `gorm:"primary_key" json:"question_id"`
QuestionText string `gorm:"not null;unique" json:"question_text"`
Options []Option
}
type Option struct {
OptionID int `gorm:"primary_key" json:"option_id"`
OptionText string `gorm:"not null;unique" json:"option_text"`
}
I'm not sure abour GORM part, but with JSON you need to add struct tags on the nested objects as well:
type Survey struct {
...
Questions []Question `json:"questions"`
}
type Question struct {
...
Options []Option `json:"options"`
}
We're missing some scope from your code, and so it's quite hard to point you in the right direction. Are you asking about querying GORM so you get []Survey, or are you asking about marshalling []Survey? Anyway, you should add the tag to Questions too, as slomek replied.
However, try this:
To fetch nested data in m2m relation
type Survey struct {
gorm.Model
SurveyID string `gorm:"primary_key" json:"survey_id"`
SurveyName string `gorm:"not null" json:"survey_name"`
Questions []*Question `gorm:"many2many:survey_questions;"`
}
surveys := []*model.Survey{}
db := dbSession.Where(&model.Survey{SurveyID: id}).Preload("Questions").Find(&surveys)

Sails.js associations

I am beginning with sails.js and I am completely lost with my sql queries.
I have the following tables :
genres
+-----------+--------------+------+-----+
| Field | Type | Null | Key |
+-----------+--------------+------+-----+
| id | int(6) | NO | PRI |
| name | varchar(100) | NO | |
| slug | varchar(255) | NO | |
| type | varchar(32) | NO | |
| parent_id | int(11) | YES | MUL |
+-----------+--------------+------+-----+
genres_radios
+----------+--------+------+-----+
| Field | Type | Null | Key |
+----------+--------+------+-----+
| genre_id | int(6) | NO | MUL |
| radio_id | int(6) | NO | MUL |
+----------+--------+------+-----+
radios
+-----------+--------------+------+-----+
| Field | Type | Null | Key |
+-----------+--------------+------+-----+
| id | int(5) | NO | PRI |
| name | varchar(100) | NO | |
| slug | varchar(100) | NO | |
| url | varchar(100) | NO | |
+-----------+--------------+------+-----+
I want to retrieve the radios and their associated genres. I managed to do it using the Model.query("Select * FROM ...") but I'd like to do it using the populate method. I had a look at the docs, but I am a bit confused with the "via", "through", ...
Well if you've followed the Sails.js Model documentation and the many-many association docs your models should look something like:
// api/models/genre.js
module.exports = {
attributes : {
name : {
type: 'string'
},
slug : {
type: 'string'
},
type : {
type: 'string'
},
radios : {
collection: 'radio',
via: 'genres'
}
}
}
// api/models/radio.js
module.exports = {
attributes : {
name : {
type: 'string'
},
slug : {
type: 'string'
},
url : {
type: 'string'
},
genres : {
collection: 'genre',
via: 'radios'
}
}
}
The many-many lookup table will be created for you internally by waterline. All you need to get the genres for your radio is populate the "genres" attribute.
Radio.findOne({name:"RadioName"}).populate("genres").then(function(radio){
console.log(radio); //radio.genres will have all the genres associated with this radio.
})
I really do recommend looking at the many-many association docs. They have exactly what you need.
This should do it :
// api/models/Genres.js
module.exports = {
attributes : {
name : {
type: 'string'
},
slug : {
type: 'string'
},
type : {
type: 'string'
},
radios : {
collection: 'Radios',
through: 'genres_radios'
}
}
}
// api/models/Radios.js
module.exports = {
attributes : {
name : {
type: 'string'
},
slug : {
type: 'string'
},
url : {
type: 'string'
},
genres : {
collection: 'genre',
through: 'genres_radios'
}
}
}
// api/models/Genres_radios.js
module.exports = {
attributes = {
'Genre_id': {
columnName:'genre_id',
type:'integer',
foreignKey:'true',
references:'genres',
on:'id',
via:'genres'
},
'Radio_id': {
columnName:'radio_id',
type:'integer',
foreignKey:'true',
references:'radios',
on:'id',
via:'radios'
}
}
}
And then you can make the following request :
Radio.findOne({name:"RadioName"}).populate("genres").then(function(radio){
console.log(radio);
})

MDX result to JSON using C#

I'm new to MDX, basically I need to serialize the SSAS MDX result to a JSON object.
MDX Query:
SELECT
(
[Measures].[Max Available]
) ON COLUMNS
, NON EMPTY
(
[Application].[Product].Children * [Application].[Application Name].Children
) DIMENSION PROPERTIES MEMBER_CAPTION ON ROWS
FROM [Applications]
Let's say I have a MDX result that looks like:
__________________________________
| | | Measure1 |
| Product1 | Feature1 | 1 |
| Product1 | Feature2 | 1 |
| Product1 | Feature3 | 10 |
| Product2 | Feature1 | 1 |
| Product2 | Feature2 | 1 |
| Product3 | Feature1 | 1 |
| Product3 | Feature2 | 1 |
| Product3 | Feature3 | 1 |
| Product3 | Feature4 | 1 |
I need to create a JSON object that looks like (I don't need the Measurement values, I just used them to get valid list of products and features in the MDX Heirarchy):
[
{
"product":"Product1",
"feature":[
"Feature1",
"Feature2",
"Feature3"
]
}, {
"product":"Product2",
"feature":[
"Feature1",
"Feature2"
]
}, {
"product":"Product3",
"feature":[
"Feature1",
"Feature2",
"Feature3",
"Feature4"
]
}, {
...
}
]
I use ADOMD.NET library using ExecuteCellSet(), but I'm also new to this one as well. Can someone point me to the right direction?
Thanks,
dfox
Although I am not familiar with MDX, I have used JSON in C#. One way to create a JSON object (since they are not native in C# as of 4.5) is by using DataContracts.
using System.Runtime.Serialization.Json;
using System.Runtime.Serialization;
namespace Interface.Data
{
[DataContract]
class jsonObject
{
[DataMember]
public String product="";
[DataMember]
public String[] feature={"", "", ""};
public jsonObject(){}
}
}
Then in your MDX query, assuming you are storing the query data in some string 'line', you can do:
using System.Runtime.Serialization.Json;
using System.Data.Common;
using System.IO;
static jsonObject json;
public static MDXObj parseMDXObj(String line)
{
MDXObj obj = new MDXObj(getMDX());
try
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(jsonObject));
MemoryStream stream = new MemoryStream(ASCIIEncoding.UTF8.GetBytes(line));
json = (jsonObject)ser.ReadObject(stream);
}
catch (Exception e)
{
Console.WriteLine("Error Occurred in creating JSON: " + e.Message);
return null;
}
return obj;
}