How to create parent child hierarchy using self-join in strongloop. I have created model name as menu.
menu.json
{
"name": "Menu",
"base": "PersistedModel",
"strict": false,
"idInjection": false,
"options": {
"validateUpsert": true
},
"properties": {
"MenuID": {
"type": "Number",
"id": true,
"required": true
},
"Name": {
"type": "string"
},
"ParentMenuID": {
"type": "Number"
}
},
"validations": [],
"relations": {
"menus": {
"type": "hasMany",
"model": "Menu",
"foreignKey": "ParentMenuID",
}
},
"acls": [],
"methods": {}
}
Table data like:
menuId Name ParentID
1 parent 0
2 child 1
3 grandchild 2
I tried REST API call using filter but I am getting one level of data like
http://localhost:3000/api/Menus/?filter[include]=menus
[
{
"MenuID": 1,
"Name": "parent",
"ParentMenuID": 0,
"menus": [
{
"MenuID": 2,
"Name": "child",
"ParentMenuID": 1
}
]
},
{
"MenuID": 2,
"Name": "child",
"ParentMenuID": 1,
"menus": [
{
"MenuID": 3,
"Name": "grandchild",
"ParentMenuID": 2
}
]
},
{
"MenuID": 3,
"Name": "grandchild",
"ParentMenuID": 2,
"menus": []
}
]
BUT I needed output like:
[
{
"MenuID": 1,
"Name": "parent",
"ParentMenuID": 0,
"menus": [
{
"MenuID": 2,
"Name": "child",
"ParentMenuID": 1,
"menus": [
{
"MenuID": 3,
"Name": "grandchild",
"ParentMenuID": 2
}
]
}
]
}
]
Please suggest any idea or example.
After you create your model with slc loopback:model, just run slc loopback:relation and create the selfjoin as a relation.
As you now have done in your updated question. To include another you use an include filter, http://localhost:3000/api/Menus/?filter[include]=menus and to include two levels you can do like this: http://localhost:3000/api/Menus/?filter[include][menus]=menus
Suppose you have a model review, images, and the relation that you want between them is review should have multiple images. Then you have to define this relation in the json files for both the models
Review.json
"relations": {
"images": {
"type": "hasMany",
"model": "Image",
"foreignKey": ""
}
}
Image.json
"relations": {
"hotelReview": {
"type": "belongsTo",
"model": "HotelReview",
"foreignKey": ""
}
}
You can also accomplish the same using slc loopback:relation after you create both the models.
Now in order to extract the data using this relation or join, you can use the filter api's provided by loopback, and in particular use the include provide by loopback.
Sample links for loopback include and filter api
https://docs.strongloop.com/display/public/LB/Include+filter
https://docs.strongloop.com/display/public/LB/Querying+data
sample filter api, using include :-
localhost:3000/api/Review?filter[where][email]=xyz#abc.com&filter[include]=images
Related
Once i rendered data from backend i want to remove element id from the array how can i achieve that using angularjs ?
ctrl.js
$scope.array = [{
"name": "Java Class",
"id": "javaClass",
"createdBy": "shu",
"__v": 0,
"properties": [{
"label": "Java Package Name",
"type": "String",
"editable": true,
"binding": {
"type": "property",
"name": "camunda:class"
}
}],
"appliesTo": ["bpmn:ServiceTask"]
}]
You can use delete
delete $scope.array[0].id;
This is a follow up question for Compare two arrays and update with the new values by keeping the existing objects using javascript which was ansewered by #Siderite Zackwehdex
Please check this plunker I'm getting the deleted Object in the changedArray1.Is there any option to fix this.Its working fine for other changes like add,update but not for delete.
One feature that I tried to implement is to add an additional object ie., "removedIds":[23] , that holds the deleted id's as an array in each level of objects and identifying them in the evaluation process.. but didn't find the right soultion
Example data:
var parentArray1=[
{
"id": 1,
"name": "test",
"context": [
{
"operationalContextId": 1.1,
"valueChainEntityDetails": [
{
"valuChainEntityId": 3,
"name": "test",
"context": [
{
"id": 3.1,
"name": "test 3.1",
"activityDetails": [
{
"activityId": 22,
"name": "test 3.1"
},
{ //trying to remove activity id 23
"activityId": 23,
"name": "changed test 23"
}
]
}
]
}
]
}
]
}
]
var changedArray1=[
{
"id": 1,
"name": "test2",
"context": [
{
"operationalContextId": 1.1,
"valueChainEntityDetails": [
{
"valuChainEntityId": 3,
"name": "changed test3",
"context": [
{
"id": 3.1,
"name": "test 3.1",
"removedIds":[23] ,
"activityDetails": [ //activity id 23 is removed in this JSON but reflecting in parentArray1
{
"activityId": 22,
"name": "changed test 3.1"
}
]
}
]
}
]
}
]
}
]
I've been trying to create a collection that contains an array of objects in loopback.
I want a store data formatted like this:
{
id: "16356135616aaasad", //autogenerated by mongo
"name" : "a name",
"valores": [
{"valor": 567, "fecha": "2016-08-18T00:00:00.000Z"},
{"valor": 569, "fecha": "2016-08-19T00:00:00.000Z"},
...
]
}
I have the following configuration in loopback:
indicador.json
{
"name": "Indicador",
"plural": "indicadores",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true,
"autoId": true
},
"properties": {
"nombre": {
"type": "string",
"required": true
}
},
"relations": {
"historico": {
"type": "embedsMany",
"model": "Valor"
}
}
}
this is a base collection associated to another model (not persistent)
valor.json
{
"name": "Valor",
"plural": "valores",
"base": "Model",
"properties": {
"valor": {
"type": "number",
"required": true
},
"fecha": {
"type": "date",
"required": true
}
}
}
The problem it's when i try to send a post to the endpoint. If i send this data
{
"nombre": "UF",
"valores": [
{
"valor": 0,
"fecha": "2016-08-18"
}
]
}
The API responses this:
{
"error": {
"name": "ValidationError",
"status": 422,
"message": "The `Indicador` instance is not valid. Details: `valores` contains invalid item at index `0`: `id` is blank (value: [ { valor: 0, fecha: 2016...} ]).",
"statusCode": 422,
"details": {
"context": "Indicador",
"codes": {
"valores": [
"invalid"
]
},
"messages": {
"valores": [
"contains invalid item at index `0`: `id` is blank"
]
}
},
"stack": "ValidationError: The `Indicador` instance is not valid. Details: `valores` contains invalid item at index `0`: `id` is blank (value: [ { valor: 0, fecha: 2016...} ]).\n at /home/dev/app/node_modules/loopback-datasource-juggler/lib/dao.js:322:12\n at ModelConstructor.<anonymous> (/home/dev/app/node_modules/loopback-datasource-juggler/lib/validations.js:492:11)\n at ModelConstructor.next (/home/dev/app/node_modules/loopback-datasource-juggler/lib/hooks.js:81:12)\n at ModelConstructor.<anonymous> (/home/dev/app/node_modules/loopback-datasource-juggler/lib/validations.js:489:23)\n at ModelConstructor.trigger (/home/dev/app/node_modules/loopback-datasource-juggler/lib/hooks.js:71:12)\n at ModelConstructor.Validatable.isValid (/home/dev/app/node_modules/loopback-datasource-juggler/lib/validations.js:455:8)\n at /home/dev/app/node_modules/loopback-datasource-juggler/lib/dao.js:318:9\n at doNotify (/home/dev/app/node_modules/loopback-datasource-juggler/lib/observer.js:98:49)\n at doNotify (/home/dev/app/node_modules/loopback-datasource-juggler/lib/observer.js:98:49)\n at doNotify (/home/dev/app/node_modules/loopback-datasource-juggler/lib/observer.js:98:49)"
}
}
¿Why i get this error?
The id inside the objects of the array that I need isn't necessary for me. I don't understand why happen this.
You need to specify that embedded model doe not need id
"relations": {
"historico": {
"type": "embedsMany",
"model": "Valor",
"options": {
"forceId": false,
"validate": true,
"persistent": false
}
}
}
You need to add "defaultFn":"uuid" to the id property in the json of the model that is going to be embeded in order to have the id generated. In your case it will look like the following:
{
"name": "Valor",
"plural": "valores",
"base": "Model",
"properties": {
"id":{
"type": "string",
"defaultFn":"uuid",
"id":true
},
"valor": {
"type": "number",
"required": true
},
"fecha": {
"type": "date",
"required": true
}
}
}
The issue I'm having is as follows: I'm attempting to populate a Javascript object (called Table) with content from another object (called Messages)
I'm trying to do this by matching 2 keys in the Table object with 2 keys from the Messages object. The keys I'm trying to match can be described as 'row' and 'cell'.
If the message 'row' and 'cell' match, I push the message into the cell.
Information
- Rows are unique keys at the top level of the object and are called 'labs'.
- Cells are unique keys in Rows, but a Cell key might have a duplicate in another row. They are called 'steps'.
My thoughts were that to uniquely identify a cell, it would be possible to compare the Row + Cell key of the Table cell I want to populate with the Row + Cell key of the message. If they match, populate the Table cell.
The object I'm trying to populate looks as following (before population):
{
"570f5233c8640c8819dae6a2": {
"570f5215c8640c8819dae6a0": {
"_id": "570f5215c8640c8819dae6a0",
"time": 2,
"type": "Type 1",
"order": 0,
"messages": []
},
"570f927196fa91ab0a1d8793": {
"_id": "570f927196fa91ab0a1d8793",
"time": 0,
"type": "Type 2",
"order": 1,
"messages": []
}
},
"570f52caecbdcb2c1a7031f1": {
"570f5215c8640c8819dae6a0": {
"_id": "570f5215c8640c8819dae6a0",
"time": 2,
"type": "Type 1",
"order": 0,
"messages": []
},
"570f927196fa91ab0a1d8793": {
"_id": "570f927196fa91ab0a1d8793",
"time": 0,
"type": "Type 2",
"order": 1,
"messages": []
}
}
}
The code I'm using to populate the object above as follows (I'm populating the messages field):
for (let msgKey in messages) {
if (messages.hasOwnProperty(msgKey)) {
for (let tableRowKey in table) {
if (table.hasOwnProperty(tableRowKey)) {
for (let cellRowKey in table[tableRowKey]) {
if (table[tableRowKey].hasOwnProperty(cellRowKey)) {
let msgRow = messages[msgKey].lab.toString();
let msgStep = messages[msgKey].step.toString();
if (tableRowKey === msgRow && cellRowKey === msgStep) {
table[tableRowKey][cellRowKey].messages.push(messages[msgKey]);
}
}
}
}
}
}
}
The output from the code looks as follows (after population):
{
"570f5233c8640c8819dae6a2": {
"570f5215c8640c8819dae6a0": {
"_id": "570f5215c8640c8819dae6a0",
"time": 2,
"type": "Type 1",
"order": 0,
"messages": [
{
"step": "570f5215c8640c8819dae6a0",
"time": 2,
"timeActual": 0.00010335648148148148,
"timeDifference": null,
"isComplete": true,
"lab": "570f5233c8640c8819dae6a2"
}
]
},
"570f927196fa91ab0a1d8793": {
"_id": "570f927196fa91ab0a1d8793",
"time": 0,
"type": "Type 2",
"order": 1,
"messages": [
{
"step": "570f927196fa91ab0a1d8793",
"time": 0,
"timeActual": 0.00007015046296296297,
"timeDifference": null,
"isComplete": true,
"lab": "570f52caecbdcb2c1a7031f1"
}
]
}
},
"570f52caecbdcb2c1a7031f1": {
"570f5215c8640c8819dae6a0": {
"_id": "570f5215c8640c8819dae6a0",
"time": 2,
"type": "Type 1",
"order": 0,
"messages": [
{
"step": "570f5215c8640c8819dae6a0",
"time": 2,
"timeActual": 0.00010335648148148148,
"timeDifference": null,
"isComplete": true,
"lab": "570f5233c8640c8819dae6a2"
}
]
},
"570f927196fa91ab0a1d8793": {
"_id": "570f927196fa91ab0a1d8793",
"time": 0,
"type": "Type 2",
"order": 1,
"messages": [
{
"step": "570f927196fa91ab0a1d8793",
"time": 0,
"timeActual": 0.00007015046296296297,
"timeDifference": null,
"isComplete": true,
"lab": "570f52caecbdcb2c1a7031f1"
}
]
}
}
}
If it was matching correctly, the message would be populated in an object when the message "lab" key and the message "step" key matched the parent keys. So a correct object would look as follows:
"570f5233c8640c8819dae6a2": {
"570f5215c8640c8819dae6a0": {
"_id": "570f5215c8640c8819dae6a0",
"time": 2,
"type": "Type 1",
"order": 0,
"messages": [
{
"step": "570f5215c8640c8819dae6a0",
"time": 2,
"timeActual": 0.00010335648148148148,
"timeDifference": null,
"isComplete": true,
"lab": "570f5233c8640c8819dae6a2"
}
]
}
However, the code is in fact populating messages in fields where the parent keys do not match, as you can see from the after population code included above.
What exactly is wrong here, to me the code looks correct, am I missing something about matching Javascript keys?
I don't know if I'm just blind or something but how can I do the following:
I have a User model with a hasOne relation to a UserData model. I only want one property of UserData directly in the results of User.
The relation in User looks like this:
"relations": {
"userData": {
"type": "hasOne",
"model": "UserData"
}
}
And the default scope in User:
"scope": {
"include": "userData"
}
So the result for one User is:
[
{
"id": 5,
"email": "example#example.com",
"name": "Example",
"userData": {
"id": 5,
"birthdate": "1971-09-06T00:00:00.000Z"
}
}
]
But what I want is this:
[
{
"id": 5,
"email": "example#example.com",
"name": "Example",
"birthdate": "1971-09-06T00:00:00.000Z"
}
]
How can I achive this?
Edit:
The two model definitions:
ChiliUser:
{
"name": "ChiliUser",
"base": "ChiliUserData",
"idInjection": true,
"options": {
"validateUpsert": true,
"mysql": {
"table": "person"
}
},
"properties": {
"id": {
"type": "number"
},
"email": {
"type": "string"
},
"password": {
"type": "string"
},
"vorname": {
"type": "string"
},
"name": {
"type": "string"
},
"spitzname": {
"type": "string"
},
"strasse": {
"type": "string"
},
"plz": {
"type": "number"
},
"ort": {
"type": "string"
},
"geolat": {
"type": "string"
},
"geolng": {
"type": "string"
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": []
}
ChiliUserData:
{
"name": "ChiliUserData",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true,
"mysql": {
"table": "person_data"
}
},
"properties": {
"id": {
"type": "number"
},
"person_id": {
"type": "number"
},
"birthdate": {
"type": "date"
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": []
}
Are you using the built-in User model? If you are, you can simply extend it with your UserData model using base: "User", and the underlying schema will be as you desire:
{
"name": "UserData",
"base": "User",
"properties": {}
...
}
But this setup would mean you'd use UserData over User in your code. Since the built-in User model gets in the way, I'd recommend a different word like Person or Customer, in which case it would look like:
{
"name": "Person",
"base": "User",
"properties": {
...extra user data properties only...
}
...
}
This way, only Person will have all the extra "user data" fields on it, but will also include all the fields/methods defined for User inside node_modules/loopback/common/models/User.json. If you're using MySQL, the Person table will be created with the combination of fields from both User and Person.