Creating model with nested objects and arrays in Loopback version LB4 - loopbackjs

I've just started with Loopback for the first time and I've started with LB4, their newest release. I'm looking to create a model with nested objects and arrays as per my JSON schema to which I followed the documentation which allowed me to create the base values of my schema, but I need to create the fields inside the objects and arrays, but I can't find the documentation or articles to help me understand this...
This is my JSON schema I'm trying to create a LB4 model with:
"socialProfiles": {
"facebook": {
"linked": 1,
"pullData": 1,
"linkID": 4434343,
"profile": "https://www.facebook.com/FBURL",
"registered": {
"date": "2018-05-04T12:41:27.838Z",
"verified": "2018-05-04T12:41:27.838Z",
"by": {
"id": 1,
"user": "USER"
}
}
},
}
Using the LB4 documentation, I can create my main field socialProfiles but I can't find where I go to create my fields inside this object... Here's my LB4 model code
import {Entity, model, property} from '#loopback/repository';
#model()
export class Users extends Entity {
#property({
type: 'object',
})
socialProfiles?: object;
constructor(data?: Partial<Users>) {
super(data)
}
}
How to do this?

If you want to store the object in the model itself (not with a relation), you can create an interface with something like:
export interface ISocialProfile {
"linked": number,
"pullData": number,
"linkID": number,
"profile": string,
"registered": {
"date": Timestamp,
"verified": Timestamp,
"by": {
"id": number,
"user": string
}
}
}
and then in your model, you can just add the type:
socialProfiles?: {[name: string]: ISocialProfile};

Related

Loopback 4 and Mongodb : All model's id are null on response

It is the first time that I use this version (4) for development and I have a problem with loopback and mongodb indexing.
Of the two ids that are inside the db loopback it does not collect any.
It's a problem of the API or DB?
Model [Loopback]
import { Entity, model, property } from '#loopback/repository';
#model()
export class Ad extends Entity {
#property({
type: 'number',
id: true,
required: true,
})
id: number;
<...>
constructor(data?: Partial<Ad>) {
super(data);
}
}
Data on Mongo:
{
"_id": {
"$oid": "5c0e9c7730146d2448746834"
},
"id": 110722,
"creation_date": 1492075600000,
"update_date": 1492075921000,
...
}
Response on loopback GET /ads
[{
"id": null,
"creation_date": 1492075600000,
"update_date": 1492075921000,
...
},...]
Hello from the LoopBack team :)
I don't see any obvious problem in the code snippets you posted. What happens when you change id's type from number to string? Will it fix the problem?
Most likely, you have found a bug in LoopBack 4. Please report it via GitHub: https://github.com/strongloop/loopback-next/issues
I fixed the same issue by changing the id=String. Mongodb id contains both string and number. So, if you change the type of id=string (Model) the issue will be fixed.

How to get Count value in a HasMany relationship when querying sub Models?

On a Category model I created, I have the following relation:
"subscriptions":
{
"type": "hasMany",
"model": "Subscription"
"foreignKey": "",
"options": { "nestRemoting": true } } }
How could I get the Count() result when running:
this.userService.getCategories(this.currentUser.id,
{include: {relation: 'subscriptions', scope: {type: 'count'}}})
.subscribe((data: any[]) => { this.categories = data };
I would like to count the number of subscription when getting the categories belonging to the user, in the same observable().
Like show above, I tried with the scope of type 'count'. nothing comes.
Thanks for any help.
As an answer:
Loopback provides the 'include' filter to be able to retrieve related models.
As a consequence an Observable is retrieved. It does contain the relationship.
Getting the Count() is as simple as writing {{category.subscriptions.length}}in the HTML.
Hope this helps.

Ember Nested Data in JSON Response

I'm having some trouble accessing some nested data in one of my Ember models. Below is the JSON response...
{
"fields": {
"header": {
"name": "header",
"type": "text",
"localize": false,
"options": []
},
"body": {
"name": "body",
"type": "textarea",
"localize": false,
"options": []
}
},
"entries": [
{
"header": "header test",
"body": "body test body test body test",
"_mby": "5a395e8430c2ddoc683600766",
"_by": "5a395e8430c2ddoc683600766",
"_modified": 1513709605,
"_created": 1513709605,
"_id": "5a3960253d578doc735798511"
}
],
"total": 1
}
Here is my current serializer
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
normalizeResponse(store, primaryModelClass, payload, id, requestType)
{
payload = {
entries: payload.entries
};
return this._super(store, primaryModelClass, payload, id, requestType);
}
});
I'm trying to get the Entries in my template. Perhaps I need some help better serializing this with NormalizeResponse? I'm very stumped so please share if you have any ideas!
Thanks!!
The ember-data RESTAdapter expects the JSON to contain keys that correspond to model names and values to be arrays of JSON objects with key-value pairs according to the respective models' attribute-name--attribute-value-type definitions*.
So if you have a model named entry containing header: attr('string'), body: attr('string'), the following JSON should lead to an entry in the store:
{
"entries": [{
"header": "header test",
"body": "body test body test body test",
"id": "5a3960253d578doc735798511"
}],
}
There is a way to convince ember-data to customize the id field name (to accept _id instead of id). The build-in pluralization rules should include the entry->entries pluralization (but I cannot vouch for it).
Any top-level key that does not correspond to a model name should be ignored anyway, so no need to filter it out manually (unless you have models named field or total).
If you then return this.store.findAll('entry') (or query('entry',{/*something*/}) in your route's model hook, you should be able to look over {{#each model as |entry|}} in your controller's template.
(It is good practice to not use model as the model name, but if you want it to be entries, you have to specify that explicitly somewhere, i.e. the controller or the route's setupController method.)
*The point of repeating the name of the model as top-level key in the json response (presumably to an API endpoint of the same name) is that you can include other models if you whish and they will be added to the store as well.

ember-data: Allow sideloaded model to contain embedded records that were just created

I’m running into an issue with the REST Adapter/Serializer and EmbeddedRecordsMixin, specifically my app needs to be able to sideload an model’s parent record in create/POST responses, and that parent model contains the child record embedded in a hasMany array. This is resulting in “You cannot update the id index of an InternalModel once set.” errors. heres a simplified version of the JSON structure my api is returning:
// POST /child-model response
{
"childModel": {
"id": 1,
"foo": "Bar"
},
"parentModel": {
"id": 2,
"children": [
{
"id": 1,
"foo": "Bar"
}
]
}
}
Is there any way to allow this type of response? Essentially I want ember-data to just treat the embedded child record as just an "update" to the record that was just created, where it is just using it to make the association between it and the parent record.

How to update links attribute in ember data dynamically?

To load async relationship ember data payload usually contains links attribute.
{
"post": {
"id": 1,
"title": "Progressive Enhancement is Dead",
"links": {
"user": "/people/tomdale"
},
},
}
In my case application have to create link itself due to the fact that it operate on date and time selected by the user. Link to the relationship is not fixed. It there any way to change model link attribute on runtime or do I really need to create whole relationship manually using Ember.$.ajax?
You can create a serializer to customize the links field. Example:
App.PostSerializer = DS.RESTSerializer.extend({
normalizePayload: function(payload) {
payload.links = {
"user": getMyLink(payload.links, payload.id)
};
return payload;
}
});
where getMyLink is your custom function.
Does this address your problem?