Using Backbone Relational to handle JSON-API Data - json

We've been using Backbone Relational to model our ORM relationship in the front end for instance:
{
id: 2
username: "bob"
comments: [
{
id:5,
comment: "hi",
user: {
username: 'Bob'
}
}
]
}
That has been working great using models such as this in the front end:
class User extends App.RelationalModel
relations: [{
type: Backbone.HasMany,
key: 'comments',
relatedModel: 'Comment',
collectionType: 'CommentCollection'
}]
However now our api has changed and respecting more of the JSON-API Spec so the data from the back end is encapsulated inside of 'data'.
{
data: {
id: 2
username: "bob"
data: {
comments: [
{
id:5,
comment: "hi",
user: {
username: 'Bob'
}
}
]
},
meta: {
}
}
}
How can we instruct backbone relational to get the data for the 'comments' relation from .data instead of mapping the json structure directly?
For the ''class User'' we can implement the parse method like so
class User
parse: (response) ->
response.data
But how do we do this for the comments relation??

How's this?
parse: function (response) {
var fixed_response = response.data;
fixed_response.comments = fixed_response.data.comments;
delete fixed_response.json.data;
return fixed_response;
}

Related

Exclude primary key attributes from a sequelize query

I have a sequelize query from multiple tables inner joined together. I need to group them by on a nested include model but the sequelize query throws the primary key every time, even if I mention the attributes as: attributes:[].
However attributes:[] is working for nested include models.
You can exclude any attributes by passing an exclude array into the attributes option:
MyModel.findAll({
attributes: {exclude: ['some_field']}
});
For included models use attributes: ['prop_name']
Remember include/exclude will not affect nested tables use through: { attributes:[]}
Model.addScope('scope_name', {
attributes: ['id', 'name'],
include: [
{
model: models.role,
as: 'roles',
attributes: ['name'],
through: {
attributes: []
}
}
]
More details can be found here: https://github.com/sequelize/sequelize/issues/4074#issuecomment-153054311
I want to add that you can explicitly list the attributes you want and that they work on nested inner joins as follows:
const my_model = await MyModel.findById(id, {
include: [
{
model: AnotherModel,
attributes: [ 'displayName', 'email' ] // only these attributes returned
},
{ model: YetAnotherModel,
include: [{
model: AnotherModel,
attributes: [ 'id', 'displayName', 'email' ]
}]
}
]
})
Your returned Object should look like:
{
// ...MyModel attributes
,
AnotherModel: {
displayName: '...',
email: '...',
},
YetAnotherModel: {
// ...YetAnotherModel's attributes
,
AnotherModel: {
id: '...',
displayName: '...',
email: '...',
}
}
}

Unable to translate created object using autodesk forge derivativesApi

I am trying to translate an object after uploading it but I keep getting 400 Bad Request error.
I am using the forge-api-nodejs-client
here is how my code looks like
var base64 = require('js-base64').Base64;
objectsApi.uploadObject(
bucket.bucketKey,
file.originalname,
file.size,
file.buffer,
{},
oAuth2TwoLegged,
credentials
)
.then(
response => {
const objectDetails = response.body;
// objectId => urn:adsk.objects:os.object:d62db090-0c47-11e8-9a36-7bd06cedf058/Pawn.stl
const job = {
input: {
urn: base64.encode(objectDetails.objectId)
},
output: {
formats: [
{
type: "obj"
}
]
}
};
derivativesApi
.translate(job, {}, oAuth2TwoLegged, credentials)
.then(
data => {
res.send(data);
},
err => {
// it fails here with 400 status error
res.send(err);
}
);
},
err => {
res.send(err);
}
);
my job object looks like this:
{
input:{
urn: 'dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6ZDYyZGIwOTAtMGM0Ny0xMWU4LTlhMzYtN2JkMDZjZWRmMDU4L1Bhd24uc3Rs'
},
output: {
formats: [
type: "obj"
]
}
}
the response
{
statusCode: 400,
statusMessage: "Bad Request"
}
I have also a tutorial using the Forge NPM to do the whole process of creating bucket to upload file and translate it. I think the part you are having problems with is the uploading part
Check this https://github.com/jaimerosales/modelderivative-nodejs-tutorial/blob/master/uploader.js#L145
Your payload is incorrect, it should look like below:
{
input: {
urn: "...place your design url here ..."
},
output:{
force: false, // true if you want to force regenerate the obj, after new model upload for ex (optional)
formats: [{
type: 'obj',
advanced: {
modelGuid: "...", // model GUID, required
objectIds: [-1] // array of dbIds to export, required. Pass [-1] to export full model, or specific dbIds ex: [49, 56, ...]
}
}],
destination: {
region: 'us' // default, optional can be ['us', 'emea']
}
}
})
You need to perform additional API call to retrieve the model GUID: see GET :urn/metadata for more details

Mongoose: TypeError: Method Uint8Array.length called on incompatible receiver

I'm making a small website with i18n. When starting I used local json files, but after switching to mongodb I experience an error I don't understand. A good explanation is highly appreciated.
The error I get is this:
TypeError: Method Uint8Array.length called on incompatible receiver [object Object]
I structure i18n data with "da" and "en" properties. I then use a method for filtering relevant language.
Here are examples of my data, both json and corresponding mongoose result. Both copied from terminal (printed with console.log):
json
[ { lang: { da: 'Dansk', en: 'Danish' }, rating: 5 },
{ lang: { da: 'Engelsk', en: 'English' }, rating: 5 },
{ lang: { da: 'Tysk', en: 'German' }, rating: 5 } ]
mongoose
[ { _id: 57e2561369e4bc0a8ca6c630,
lang: { da: 'Dansk', en: 'Danish' },
rating: 5,
id: '57e2561369e4bc0a8ca6c630' },
{ _id: 57e2561369e4bc0a8ca6c631,
lang: { da: 'Engelsk', en: 'English' },
rating: 5,
id: '57e2561369e4bc0a8ca6c631' },
{ _id: 57e2561369e4bc0a8ca6c632,
lang: { da: 'Tysk', en: 'German' },
rating: 5,
id: '57e2561369e4bc0a8ca6c632' } ]
filterLanguage method
var traverse = require('traverse');
var filterLanguage = function(language, obj) {
return traverse(obj).map(function (item) {
if (this.key === language) {
this.parent.update(item);
}
});
};
So filterLanguage('da', languages); should return something like:
[ { lang: 'Dansk', rating: 5 },
{ lang: 'Engelsk', rating: 5 },
{ lang: 'Tysk', rating: 5 } ]
filterLanguage() works on a local, valid JSON file but not on the Mongoose result set...
I tried JSON.stringify(obj). I also tried setting toObject() method in Mongoose models but no luck.
What am I doing wrong and how can I fix it?
--------- EDIT ---------
Model
var mongoose = require('mongoose');
var languageSchema = mongoose.Schema({
local: {
lang: { da: String, en: String },
rating: Number
}
});
module.exports = mongoose.model('Language', languageSchema);
Query
language.find({}, function(err, results) {
var obj = filterLanguage(lang, results.languages);
console.log(obj);
});
I tried setting toObject on the schema like this:
languageSchema.set('toObject', { virtuals: true });
The error you get is related to traverse not being able to handle ObjectId instances in your results array.
Since it looks like you don't use _id or id, the easiest way to fix this is to exclude those properties from the result documents:
language.find({}, '-_id -id', function(err, results) { ... })
(-id is probably superfluous, because it's a virtual that depends on _id)

NodeJS parsing json objects from twitter

I am looking to grab some information from the data twitter provides. Im looking to extract all the screen names that come out of this object.
T.get('followers/list', { screen_name: 'screenname' }, function (err, data, response) {
console.log(data);
});
You will receive this in the object :
{ users:
[ { id: 1234,
id_str: '1234',
name: 'Name',
screen_name: 'screenName123',
location: '....',
profile_location: null,
description: '....',
url: '...',
entities: [Object],
protected: false,
followers_count: 1751,
friends_count: 2001,
.
.
.
.
. } ] }
How can I abstract just screen_name out of this object. data.users.screen_name returns undefined.
As you can see from the console output, data.users is an array. So if you want the screen_name of the first element then just use: data.users[0].screen_name

Root property of a nested JSON or model in sencha

i have a json in the following format:
{
"collection": [
{
"id": 4,
"tickets": {
"collection": [
{
"inner_id": 8,
},
{
"inner_id": 10,
}
],
"count": 2,
"type": "collection"
},
},
{
"id": 5,
"tickets": {
"collection": [
{
"inner_id": 1,
},
{
"inner_id": 2,
}
],
"count": 2,
"type": "collection"
},
},
]
}
For this particular JSON i created the models as:
Ext.define("myProject.model.ABC", {
extend: "Ext.data.Model",
config: {
idProperty: "id",
fields:[
{name: "id", type: "int" },
],
hasMany: [
{
model: "myProject.model.XYZ",
name: "tickets",
associationKey: "tickets",
},
],
}
});
And second store as:
Ext.define("myProject.model.XYZ", {
extend: "Ext.data.Model",
config: {
// idProperty: "id",
fields:[
{name: "inner_id", type: "int" },
],
belongsTo: 'myProject.model.ABC'
}
});
But now i am confused. How do i populate the second store with a root property of collection again.
I know one way is to easily change the json so that there is no collection child inside tickets but i dont want to do that.
Any help would be appreciated. I have simplified the JSON for an easy example.
EDIT:
To be more clear, is there a way i can directly create a model which will read the Collection array inside the tickets object.
EDIT:
Adding the store which populates the model ABC for more understanding
Ext.define("myProject.store.ABCs", {
extend: "Ext.data.Store",
config: {
model: "myProject.model.ABC",
autoLoad: false,
proxy: {
type: "ajax",
url: '', //myURL
reader: {
type: "json",
rootProperty: "collection", // this is the first collection
},
},
}
});
This store loads the ABC model correctly but now i want to load the XYZ model which can load the inner array of collection
belongsTo should be define as follows :
Ext.define('Product', {
extend: 'Ext.data.Model',
fields: [
{ name: 'id', type: 'int' },
{ name: 'category_id', type: 'int' },
{ name: 'name', type: 'string' }
],
associations: [
{ type: 'belongsTo', model: 'Category' }
]
Have you read the doc? They specified the root property.
The name of the property which contains the data items corresponding to the Model(s) for which this Reader is configured. For JSON reader it's a property name (or a dot-separated list of property names if the root is nested). For XML reader it's a CSS selector. For Array reader the root is not applicable since the data is assumed to be a single-level array of arrays.
By default the natural root of the data will be used: the root JSON array, the root XML element, or the array.
The data packet value for this property should be an empty array to clear the data or show no data.
Sometimes the JSON structure is even more complicated. Document databases like CouchDB often provide metadata around each record inside a nested structure like this:
{
"total": 122,
"offset": 0,
"users": [
{
"id": "ed-spencer-1",
"value": 1,
"user": {
"id": 1,
"name": "Ed Spencer",
"email": "ed#sencha.com"
}
}
]
}
In the case above the record data is nested an additional level inside the "users" array as each "user" item has additional metadata surrounding it ('id' and 'value' in this case). To parse data out of each "user" item in the JSON above we need to specify the record configuration like this:
reader: {
type : 'json',
root : 'users',
record: 'user'
}
root as a Function
reader: {
type : 'json',
root : function (obj) {
// I can't reproduce your problem
// so you should check in your console collection.id is right
return obj.collection.id
}
}
// Or, we can use dot notation
reader: {
type : 'json',
root : collection[0].tickets.collection
}
There are two ways to solve this problem. After researching extensively, i found two solutions...
SOLUTION 1:
Instead of making a second model, just create one model and create an array field with type as "auto"
Ext.define("myProject.model.ABC", {
extend: "Ext.data.Model",
config: {
idProperty: "id",
fields:[
{name: "id", type: "int" },
{ name: "tickets", convert: function(value, record) {
if(value.collection instanceof Array) {
return value.collection;
} else {
return [value.collection]; // Convert to an Array
}
return value.collection;
}
}
],
}
});
Now you can refer to an array of tickets from records by:
record.get('tickets')
SOLUTION 2:
Create three model instead of two.
Model 1:
hasOne Association with Tickets
Model 2:
hasMany association with Collection
Model 3:
has all the fields of the innermost array
I can give an example if its not clear enough