Loopback REST findById doesn't work well - node.js

I'd like to use findById function through REST API.
I defined "ID" as string all constructed by number.
I try to find by ID, the system seems to recognize it number.
I can't use it when the ID is a big number over "9007199254740992" - max number of integer.
I'd like to use ID just as string.
Please tell me how to solve this problem.
Thank you,
--follow up--
My program is as follow.
Model - sample-model.json
{
"name": "SampleModel",
"base": "PersistedModel",
"idInjection": true,
"properties": {
"id": {
"type": "string",
"id": "true",
"required": true,
"doc": "MODEL ID"
},
"prop1": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": []
}
When I access to findById function through REST API, I always get following debug message.
strong-remoting:shared-method - findById - invoke with +11ms [ 9007199254740992, undefined, [Function: callback] ]
strong-remoting:shared-method - findById - result null +25ms
strong-remoting:rest-adapter Invoking rest.after for SampleModel.findById +6ms
express:router restRemoteMethodNotFound : /api/SampleModels/9007199254740993 +143ms
express:router restUrlNotFound : /api/SampleModels/9007199254740993 +8ms
express:router restErrorHandler : /api/SampleModels/9007199254740993 +2ms
strong-remoting:rest-adapter Error in GET /SampleModels/9007199254740993: Error: Unknown "SampleModel" id "9007199254740993".

I resolved my question by myself.
We can define arguments that the remote method accepts using "accepts" option.
Built-in findById function defines as follow at PersistedModel:
accepts: [
{ arg: 'id', type: 'any', description: 'Model id', required: true,
http: {source: 'path'}},
{ arg: 'filter', type: 'object',
description: 'Filter defining fields and include'}
],
When the type is defined any, the id changes to number by HttpContext.coerce function - if the id consists only number chars.
To solve this problem, I defines SampleModel.findByIdCustom and create another remote method as follow:
SampleModel.js
SampleModel.findByIdCustom = function(id, filter, cb) {
SampleModel.findById(id, filter, cb);
}
//Define remote method
SampleModel.remoteMethod(
'findByIdCustom',
{
description: 'Find a model instance by id from the data source.',
accessType: 'READ',
accepts: [
{ arg: 'id', type: 'string', description: 'Model id', required: true,
http: {source: 'path'}},
{ arg: 'filter', type: 'object',
description: 'Filter defining fields and include'}
],
returns: {arg: 'data', type: 'user', root: true},
http: {verb: 'get', path: '/:id'},
rest: {after: SampleModel.convertNullToNotFoundError},
isStatic: true
}
);
//disable built-in remote method
SampleMethod.disableRemoteMethod('findById', true);
Thank you,

Just set idInjection to false (so that loopback doesnt automatically add an id property to your model), then define a property with the following parameters:
{
"idInjection": false,
"properties": {
"id": {
"type": "string",
"id": true,
"generated": true
}
}
}

Related

How to use String properties in fastest-validator

Link: https://www.npmjs.com/package/fastest-validator
I'm using fastest-validation in my NodeJS application. I've been having great success with it. Unfortunately, I'm running into an issue that I can't seem to figure out.
If you take a look under String (located here: https://www.npmjs.com/package/fastest-validator#user-content-string)
I'm attempting to utilize the property numeric as I have a string that is a number that I would like to validate. I'm not able to find any examples, so I was left with the assumption I must set the property to true. This doesn't appear to work as I've tried to validate this theory by also setting another field that is a numeric string and set the property of alpha to true. I fully expected my 'label' to pass and my 'value' field to fail. But both passed.
How are you supposed to used these properties?
See below for my code:
buildSchema.catalogPages = {
type: "array", items: {
type: "object", props: {
label: { type: "string", empty: false, numeric: true },
value: { type: "string", empty: false, alpha: true }
}
}
}
const v = new Validator()
const check = v.compile(buildSchema)
check(valuesToCheck)
Here is my data:
const valuesToCheck = [
{
label: "9"
value: "9"
},
{
label: "12"
value: "12"
},
EDIT
I just figured out my issue. I have a handler function that checks my schemas and valuesToCheck. What I was doing was returning the check(valuesToCheck) with the assumption it simply returns true or false. But in fact, if the check fails, it returns an array of what failed (which is awesome). I'm going to accept tam.teixeira's answer as it helped me realized I need to update my handler to check if it's a Boolean true or an array (aka it failed).
I think that should not be something related to the schema itself, in the following example:
const Validator = require('fastest-validator');
const schema = {
myItems: {
type: 'array',
items: {
type: 'object',
props: {
label: { type: 'string', empty: false, numeric: true },
value: { type: 'string', empty: false, alpha: true },
},
},
},
};
const valuesToCheck = {
myItems: [
{
label: '9',
value: '9',
},
{
label: '12',
value: '12',
},
],
};
const v = new Validator();
const check = v.compile(schema);
console.log(JSON.stringify(check(valuesToCheck), null, 4));
Indeed it fails validation with errors:
$> node fastestValidatorTest.js
[
{
"type": "stringAlpha",
"message": "The 'myItems[0].value' field must be an alphabetic string.",
"field": "myItems[0].value",
"actual": "9"
},
{
"type": "stringAlpha",
"message": "The 'myItems[1].value' field must be an alphabetic string.",
"field": "myItems[1].value",
"actual": "12"
}
]
So i got your expected behaviour: "'label' to pass and my 'value' field to fail"
So my conclusion is that maybe something is not right in the buildSchema.catalogPages part, to me it feels a bit suspiscious and i also got the expected behaviour with your example, but i've changed the schema object to be simpler.
PS: Thanks for the question i didn't knew the library, so learned something new, which is cool

Update numeric and float fields in elasticsearch client

I am bit new to elasticsearch client.
I have not done any type of predefined mapping to any field, because I might add some new field to the documents in future.
My data looks like this:-
{
"segmentId": "4700-b70e-881",
"segmentName": "test",
"data": "This is a test data",
"dataId": "70897e86-9d69-4700-b70e-881a7f74e9f9",
"augmented": false,
"createdBy": {
"email": "2010abinas#gmail.com",
"primaryKey": "902d2b57-54e6",
"secondaryKey": "adcc-f20423822c93"
},
"status": "active",
"createdAt": 1617422043554,
"updatedAt": 1617422043554
}
I wanted to update 3 fields by using updateByQuery.
I was trying below approach.
await esClient.updateByQuery({
index: "data",
type: "doc",
refresh: true,
body:{
query:{
match: {
dataId: "70897e86-9d69-4700-b70e-881a7f74e9f9"
}
},
script:{
lang:"painless",
source:`ctx._source.data='This is updated test data';ctx._source.updatedAt=${Date.now()};ctx._source.segmentId=null`
}
}
})
I am getting compilation error because of updatedAt and segmentId, When I pass as string it works, like:-
source:`ctx._source.data='This is updated test data';ctx._source.updatedAt='${Date.now()}';ctx._source.segmentId='null'`
I found a way to solve the above issue,
await esClient.updateByQuery({
index: "data",
type: "doc",
refresh: true,
body:{
query:{
match: {
dataId: "70897e86-9d69-4700-b70e-881a7f74e9f9"
}
},
script:{
lang:"painless",
source:`ctx._source.data='This is updated test data';ctx._source.updatedAt=params.date;ctx._source.segmentId=params.segmentId`,
params:{
date: Date.now(),
segmentId: null
}
}
}
});

UI layer pagination and sorting in extjs

I have my extjs application. As of now i am getting all my records from backend, full record set in 1 service request. I need to implement the pagination and sorting at UI level. Sorting seems be simple. How do i implement UI level pagination? Any example for this? I am getting 10-20k records so it is fine if i implement pagination at UI level? Can extjs6 handle the load?
I'd recommend you handle paging server-side. Right now you might only have 10-20k records, but what if it grows to 100k? or 1 million?
Take a look at this guide from Sencha: Grids - Paging. It explains a lot.
Good luck!
Sorting is implemented out of box. This is simple pagination example based on default ExtJs 6.2.0 application.
YourAppName.view.main.List
...
// bottom paging-bar definition. Use "tbar" for top bar, or define both.
bbar: {
xtype: 'pagingtoolbar',
displayInfo: true,
emptyMsg: 'No data to display',
items: ['->'],
prependButtons: true
}
...
items: [{
title: 'Home',
iconCls: 'fa-home',
layout: 'fit', // needed for scrolling
scrollable: true, // for scrollable items
items: [{
xtype: 'mainlist'
}]
}, {
...
YourAppName.store.Personnel
Ext.define('YourAppName.store.Personnel', {
extend: 'Ext.data.Store',
alias: 'store.banners',
autoLoad: true, // run ajax-query right after grid rendering
loadMask: true, // show preload image
pageSize: 100,
model: 'YourAppName.model.Person',
proxy: {
type: 'ajax',
url: '/personnel',
reader: {
type: 'json',
rootProperty: 'items',
totalProperty: 'total'
}
}
});
Create in app/model folder file Person.js with:
YourAppName.model.Person
Ext.define('YourAppName.model.Person', {
extend: 'Ext.data.Model',
fields: [
{ name: 'name', type: 'string', defaultValue: '' },
{ name: 'email', type: 'string', defaultValue: '' },
{ name: 'phone', type: 'string', defaultValue: '' }
]
});
As of store definition your web-server must be able to response on HTTP GET-request on URI /personnel with json like this:
{
"success": true,
"total": 20000,
"items": [
{ "name": "Jean Luc", "email": "jeanluc.picard#enterprise.com", "phone": "555-111-1111" },
{ "name": "Worf", "email": "worf.moghsson#enterprise.com", "phone": "555-222-2222" },
{ "name": "Deanna", "email": "deanna.troi#enterprise.com", "phone": "555-333-3333" },
{ "name": 'Data', "email": "mr.data#enterprise.com", "phone": "555-444-4444" }
...
]
}

How to create many to many relationship between models in loopback?

I might be missing something obvious here but have spent hours on this and unable to find a solution.
Suppose I have an employee model
"properties": {
"name": {
"type": "string",
"required": true
},
"age": {
"type": "number",
"required": true
}
};
and its child model
"properties": {
"Code": {
"type": "string",
"required": true
},
"Desc": {
"type": "string",
"required": true
}
}
How do I create a many to many relationship between them?
You can add accepted properties passing accepts fields to remoteMethod options.
Read this page in the documentation.
module.exports = function(Task) {
fs.readdir(PATH_PROCESS+PATH_API, (err, o) => {
for(var c in o){
var i = o[c];
Task[i] = require(PATH_PROCESS+i+".js").lpb;
Task.remoteMethod(
    i, {
http: {path: ('/'+i), verb: 'post'},
returns: {arg: 'result', type: 'object'},
accepts: [
{arg: 'params', type: 'object', required: true, http: {source: 'body'},
description: (i+' params.')}
]
    }
    );
}
});
};
From the docs:
A hasManyThrough relation sets up a many-to-many connection with another model. This relation indicates that the declaring model can be matched with zero or more instances of another model by proceeding through a third model.
Use slc loopback:relation command to create relations between models. Don't forget to add through model when prompted (also explained in docs).
After you create relation between your models you will have to synchronize your changes with database using automigrate() or autoupdate().
Be careful when using automigrate because it will create or re-create your database which means that you can potentially loose your data.

node.js odata-server mongodb unable to post related entity

I have been working on a node.js odata server based on this example: How to set up a nodejs OData endpoint with odata-server
I have everything working... I can read, update, insert, delete. But I am trying to associate a Journal with a Tasks and I am having problems.
I have tried several different ways outlined here: Operations (OData Version 2.0)
Here is my code:
/* global $data */
require('odata-server');
$data.Class.define("Task", $data.Entity, null, {
Id: { type: "id", key: true, computed: true, nullable: false },
Title: { type: "string", required: true, maxLength: 200 },
Journals: { type: "array", elementType: "Journal"
, inverseProperty: "Task" }
});
$data.Class.define("Journal", $data.Entity, null, {
Id: { type: "id", key: true, computed: true, nullable: false },
Entry: { type: "string" },
DateInserted: { type: "string" },
Task: { type: "object", elementType: "Task" , inverseProperty: "Journals" }
});
$data.EntityContext.extend("obb", {
Tasks: { type: $data.EntitySet, elementType: Task },
Journals: { type: $data.EntitySet, elementType: Journal }
});
$data.createODataServer(obb, '/api-v0.1', 2046, 'localhost');
Question:
Is this feature even available from odata-server what would the post look like to link a Journal to a Task?
I am using fiddler2 and composing a POST I have tried these urls:
//localhost:2046/api-v0.1/Tasks('the-id-of-a-task')/Journals
//localhost:2046/api-v0.1/Tasks('the-id-of-a-task')/Journals/$link
post body's I have tried:
{"Entry":"This is a test"}
{"url":"http://localhost:2046/api-v0.1/Journals('id-of-a-journal-in-the-db')"}
I have even tried to build out and post a Task with journals together and that didn't work.
Any help would be greatly appreciated. Thanks.

Resources