Serializing/Deserializing nested Backbone Relational models to JSON - json

Given the following RelationalModel model:
var Server = Backbone.RelationalModel.extend({
relations: [{
type: Backbone.HasMany,
key: 'databases',
relatedModel: 'Database',
collectionType: 'DatabaseCollection',
includeInJSON: 'id'
}],
defaults: {
databases: []
},
});
var Database = Backbone.RelationalModel.extend({});
var DatabaseCollection = Backbone.Collection.extend({
model: Database
});
And these objects:
new Database({
id: 1,
name: 'DB1'
});
new Database({
id: 2,
name: 'DB2'
});
var s1 = new Server({
id: 3,
name: 'S1',
databases: [1,2]
});
What would be the easiest/recommended way to serialize/deserialize this model to something aproaching this JSON structure?:
{
databases: [
{ id: 1, name: 'DB1' }
{ id: 2, name: 'DB2' }
],
servers: [
{ id: 3, name: 'S1', databases: [1, 2] }
]
}
Such that the data can be sent to / read from the server in a single request.
Thanks!
Tim

I was able to produce the JSON you described using your example with some minor changes in this fiddle I just created Example.
I made these changes due to some warnings that were being shown in the debugger and to get the result you described. Hope this helps.
Moved the declaration of Database Model and DatabaseCollection to top before Server since Servers relatedModel and CollectionType point to those Models.
For relatedModel and collectionType instead of using Strings used the reference to Database and DatabaseCollection
Created a collection for Servers called ServerCollection
Added a few more examples
Here is the code you end up with, I just created a plain old Backbone model to combine the two collection into one. Calling toJSON gives you the single JSON object to transmit to the server.
var Database = Backbone.RelationalModel.extend({});
var DatabaseCollection = Backbone.Collection.extend({
model: Database
});
var Server = Backbone.RelationalModel.extend({
relations: [{
type: Backbone.HasMany,
key: 'databases',
relatedModel: Database,
collectionType: DatabaseCollection,
includeInJSON: 'id'
}],
defaults: {
databases: []
}
});
var ServerCollection = Backbone.Collection.extend({
model: Server
});
var allDatabases = new DatabaseCollection();
allDatabases.add([
new Database({ id: 1, name: 'DB1' }),
new Database({ id: 2, name: 'DB2' }),
new Database({ id: 3, name: 'DB3' }),
new Database({ id: 4, name: 'DB4' })
]);
var allServers = new ServerCollection();
allServers.add([
new Server({
id: 30,
name: 'S1',
databases: [
allDatabases.get(1),
allDatabases.get(2)
]
}),
new Server({
id: 40,
name: 'S2',
databases: [
allDatabases.get(3),
allDatabases.get(4)
]
})
]);
// combine into an object to transfer to server as one
var serverObject = new Backbone.Model({
'servers': allServers,
'databases': allDatabases
});
console.log(serverObject.toJSON());

Related

Dart| json formatting

I have been trying to fetch data out of JSON in flutter application.
I have tested the API request and formatting in python before making the application and all seems right
Python code:
for data in results['sections']:
for restaurant in data['items']:
restaurantName = restaurant['title']
restaurantImage = restaurant['image']['url']
for detail in restaurant:
if detail == 'venue':
restaurantAddress = restaurant['venue']['address']
restaurantDeliveryPrice = restaurant['venue']['delivery_price']
restaurantDeliveryETA = restaurant['venue']['estimate_range']
restaurantOnline = restaurant['venue']['online']
restaurantTags = restaurant['venue']['tags']
but when trying to get the data in flutter it doesn't return any feedback after
"for detail in restaurant:"
Dart code :
for (var data in jsonResponse['sections']) {
for (var restaurant in data['items']) {
var restaurantName = restaurant['title'];
var restaurantImage = restaurant['image']['url'];
print(restaurant);
}
}
Example restaurant json:
{filtering: {filters: [{id: primary, values: [hummus, kosher-for-passover, kosher]}]}, image: {blurhash: j6RIaL4iPuN3XKHdlktkX;OWgOmY, url: https://prod-wolt-venue-images-cdn.wolt.com/5fc619b23e62b6b24328928f/e122a0f8-3897-11eb-8333-de04af82ec5b_list1.jpg, variants: [xs, sm, md, frontpage]}, link: {target: 5fc619b23e62b6b24328928f, target_sort: default, target_title: , title: , type: venue-id, venue_mainimage_blurhash: j4OXin0g6J00Tl;;;mch7vgPV2WX}, overlay: Temporarily offline, sorting: {sortables: [{id: delivery-price, value: 1013}, {id: rating, value: 846}, {id: delivery-estimate, value: 946}, {id: distance, value: 1016}]}, template: venue-large, title: Hummus Hakerem | Shoken, track_id: venue-hummus-hakerem, venue: {address: שוקן 30 תל אביב , badges: [{text: KOSHER, variant: secondary}], categories: [], city: , country: ISR, currency: ILS, delivers: false, delivery_price: ₪18.00, delivery_price_highlight: false, delivery_price_int: 1800, estimate: 30, estimate_range: 25-35, franchise: , id: 5fc619b23e62b6b24328928f, location: [34.7720054, 32.0515629], name: Hummus Hakerem | Shoken, online: false, price_range: 1, product_line: restaurant, promotions: [], rating: {rating: 4, score: 9.2}, short_description: Simply great hummus, show_wolt_plus: false, slug: hummus-hakerem, tags: [kosher]}}
when trying to program the "for detail in restaurant:" loop in dart the app just loop endlessly

PUT Request with Query Parameters using InMemoryDatabase Angular 8

I am trying to make a PUT request for an object that doesn't contain an exact 'id' key. I am using the Angular InMemory Database service. The Object structure is as follows:
{
students: [{
name: 'jim',
age: 10,
grade: 4,
},{
name: 'james',
age: 11,
grade: 5,
}]
}
Service Method
updateStudent(student: Student) {
const url = 'api/students'
const options = { name: student.name };
return this.httpClient.put(url, student, { params: options }).pipe(
tap(_ => console.log('student updated)),
catchError(this.handleError('updating student'))
);
}
Component Method
updateStudent() {
this.studentService.updateStudent(this.selectedStudent).subscribe();
}
Where selectedStudent is:
{
name: 'jim',
age: 12,
grade: 6
}
If I change the PUT to a GET the in memory database come back with the correct student in the array. But with the code stated above I get a 404 Error

What InMemoryDbService is for? angular 6

Im trying to get more than one object from In Memory Data service and i cant manage to do that, just wondering if it is even possible to get? or i just can have one testing data without possibility to extend it it looks like that:
import { InMemoryDbService } from 'angular-in-memory-web-api';
export class InMemoryDataService implements InMemoryDbService {
createDb() {
const groups = [
{id: 0, name: 'Mr. Nice'},
{id: 12, name: 'Narco'},
{id: 13, name: 'Bombasto'},
{id: 14, name: 'Celeritas'},
{id: 15, name: 'Magneta'},
{id: 16, name: 'RubberMan'},
{id: 17, name: 'Dynama'},
{id: 18, name: 'Dr IQ'},
{id: 19, name: 'Magma'},
{id: 20, name: 'Tornado'},
];
return {groups}
}
}
If you want to get the whole array from the InMemoryDbService you need to send a http get request to the address: 'api/groups'.
In case you want only a specific object returned from the list you need to send a http get request to the address: 'api/groups/id' where id is one of the numbers defined in your groups const.
In case you meant to add another collection to the InMemoryDbService, you can just define a new const array and then add it to the return part of the createDb method like this:
const itemList = [
{id: 1, name: "First item"},
{id: 2, name: "Second item"},
];
return {
groups: groups,
items: itemList
}
Note that the endpoints now are: 'api/groups', 'api/groups/id', 'api/items' and 'api/items/id' where id is one of the numbers defined in your const arrays.
You also need to register the InMemoryWebApiModule in the imports array of your app.module.ts:
imports: [
InMemoryWebApiModule.forRoot(InMemoryDbService)
],

Correct normalizer syntax for normalizing JSON

I'm trying to use normalizer to normalize some JSON. My JSON looks like
total: 8029,
items: [
{
id: 1,
name: 'Jacket1',
sku: '123',
upc: '1',
price: '99.99',
images: ['url1', 'url2'],
category: 'clothing',
thumbnail:
'https://cdn.zeplin.io/5969021e44c5978909d5278b/assets/1CE5FF07-E70F-4413-85BF-49C08AA559DE.png',
}, ...
and from the examples, I thought this might work
const itemSchema = new schema.Entity('items')
const itemsSchema = new schema.Entity('result', {
items: [itemSchema],
})
const foo = normalize(fakeDatabase, itemsSchema)
But I end up with one result that is undefined, and that undefined value has some funky stuff in it.
What am I doing wrong?
I don't believe itemsSchema is necessary. Try either:
normalize(fakeDatabase, { items: new schema.Array(itemSchema) })
or
normalize(fakeDatabase, { items: [itemSchema] })

Ember Data: Saving relationships

I need to save a deep object to the server all at once and haven't been able to find any examples online that use the latest ember data (1.0.0-beta.4).
For example, with these models:
(jsfiddle)
App.Child = DS.Model.extend({
name: DS.attr('string'),
age: DS.attr('number'),
toys: DS.hasMany('toy', {async:true, embedded:'always'}),
});
App.Toy = DS.Model.extend({
name: DS.attr('string'),
child: DS.belongsTo('child')
});
And this code:
actions: {
save: function(){
var store = this.get('store'),
child, toy;
child = store.createRecord('child', {
name: 'Herbert'
});
toy = store.createRecord('toy', {
name: 'Kazoo'
});
child.set('toys', [toy]);
child.save();
}
}
It only saves the JSON for the child object but not any of the toys -- not even side loaded:
{
child: {
age: null
name: "Herbert"
}
}
Do I have to manually save the toys too? Is there anyway that I can have it send the following JSON to the server:
{
child: {
age: null
name: "Herbert",
toys: [{
name: "Kazoo"
}]
}
}
Or
{
child: {
age: null
name: "Herbert",
toys: [1]
}
}
See JSFiddle: http://jsfiddle.net/jgillick/LNXyp/2/
The answers here are out of date. Ember Data now supports embedded records, which allows you to do exactly what you're looking to do, which is to get and send the full object graph in one big payload. For example, if your models are set up like this:
App.Child = DS.Model.extend({
name: DS.attr('string'),
age: DS.attr('number'),
toys: DS.hasMany('toy')
});
App.Toy = DS.Model.extend({
name: DS.attr('string'),
child: DS.belongsTo('child')
});
You can define a custom serializer for your Child model:
App.ChildSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
toys: {embedded: 'always'}
}
});
This tells Ember Data that you'd like 'toys' to be included as part of the 'child' payload. Your HTTP GET response from your API should look like this:
{
"child": {
"id": 1,
"name": "Todd Smith",
"age": 5,
"toys": [
{"id": 1, "name": "boat"},
{"id": 2, "name": "truck"}
]
}
}
And when you save your model, Ember Data will send this to the server:
{
"child":{
"name":"Todd Smith",
"age":5,
"toys":[
{
"id":"1",
"name":"boat",
"child":"1"
},
{
"id":"2",
"name":"truck",
"child":"1"
}
]
}
}
Here is a JSBin that demonstrates this.
http://emberjs.jsbin.com/cufaxe/3/edit?html,js,output
In the JSbin, when you click the 'Save' button, you'll need to use the Dev Inspector to view the request that's sent to the server.
toys can't be both async and embedded always, those are contradicting options. Embedded only exists on the active model serializer currently.
toys: DS.hasMany('toy', {embedded:'always'})
the toys are a ManyToOne relationship, and since the relationship exists on the belongsTo side it is more efficient to save the relationship during the toy's save. That being said, if you are creating it all at once, then want to save it in one big chunk that's where overriding comes into play.
serializeHasMany: function(record, json, relationship) {
var key = relationship.key;
var relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship);
if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany' ||
relationshipType === 'manyToOne') {
json[key] = get(record, key).mapBy('id');
// TODO support for polymorphic manyToNone and manyToMany relationships
}
},
And your save should be like this
var store = this.get('store'),
child, toy;
child = store.createRecord('child', {
name: 'Herbert'
});
toy = store.createRecord('toy', {
name: 'Kazoo'
});
child.get('toys').pushObject(toy);
child.save().then(function(){
toy.save();
},
function(err){
alert('error', err);
});
I needed a deep object, instead of a side-loaded one, so based on kingpin2k's answer, I came up with this:
DS.JSONSerializer.reopen({
serializeHasMany: function(record, json, relationship) {
var key = relationship.key,
property = Ember.get(record, key),
relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship);
if (property && relationshipType === 'manyToNone' || relationshipType === 'manyToMany' ||
relationshipType === 'manyToOne') {
// Add each serialized nested object
json[key] = [];
property.forEach(function(item, index){
json[key].push(item.serialize());
});
}
}
});
Now when you call child.serialize(), it will return this object:
{
child: {
name: "Herbert",
toys: [
{
name: 'Kazoo'
}
]
}
}
Which is what I need. Here's the jsfiddle with it in action: http://jsfiddle.net/jgillick/LNXyp/8/