Sails 1.0 Models without primary key - sails.js

I try to use new version 1.0 and refactoring my project. I have one problem and i don't now how i can solve her. Some tables on my BD don't have primary keys and when i migrate to sails 1.0, i have this error
In model friends: The primary key is set to id, but no such
attribute was found on the model. You must define an id attribute in
api/Friends.js or in config/models.js. See
http://sailsjs.com/upgrading#?changes-to-model-configuration for
info
Can i use my model without primary keys?

i have the same problem i used to change the primarykey this:
in file config/model.js
attributes: {
id: {
type: 'number',
autoIncrement: true,
},
}
and in the model api/any_model.js i used:
tableName : 'table',
attributes: {
id: {
type: 'number',
columnName : 'column_you_like_to_be_a_primaryKEY',
required : true
},
}

Related

Auto increment in postgres/sequelize

I have a Postgres database using Sequelize (node/express) as ORM. I have a table called students, in it there are columns: id and name.
In this students table, I have several registered students, but a detail: the last registered ID is 34550 and the first is 30000, they come from an import from a previous database, I need to continue counting from 34550, or that is, from the last registered student. However, when I register a student via API, the generated ID is below 30000. I know that in mysql the ID field being AUTO INCREMENT would solve it, however, as I understand it, postgres works in a different way.
How could I solve this problem?
The migration used to create the table is as follows:
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('students', {
id: {
type: Sequelize.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true,
},
name: {
type: Sequelize.STRING,
allowNull: false,
},
});
},
down: (queryInterface) => {
return queryInterface.dropTable('students');
},
};
Table print:
Based on Frank comment, I was able to adjust using:
SELECT setval('public.students_id_seq', 34550, true);

LoopBack4 MongoDB Auto Increment custom ID

LoopBack itself is new for me and I see version 4 is way too different from version 3. My requirement is that I need to have a custom auto incremented id in my mongoDB document every time I create a POST to the REST end point similar to a running id in a MySQL database.
I did check this (auto-increment using loopback.js and MongoDB) and (https://gist.github.com/drmikecrowe/5a5568930bad567d4148aad75c94de5a) with a version 3 setup, but i did not find proper document to replicate the same on version 4.
Currently I am using a basic app with the out of the box REST implementations provided from the loopback 4. Below is an example of my model.
export class Test extends Entity {
#property({
type: 'string',
id: true,
})
_id?: string;
#property({
type: 'number',
generated: true,
required: false
})
id: number;
#property({
type: 'string',
required: true,
})
name: string;
#property({
type: 'boolean',
required: true,
})
val: boolean;
constructor(data?: Partial<Test>) {
super(data);
}
}
My mongodb document should look something like this:
{
"_id" : ObjectId("5c373c1168d18c18c4382e00"),
"id" : 1
"name" : "aaaa",
"val" : true
}
{
"_id" : ObjectId("5c3869a55548141c0c27f298"),
"id" : 2
"name" : "bbbbb",
"val" : false
}
You can do something like in this example
#post('/characters', {
responses: {
'200': {
description: 'Character model instance',
content: {'application/json': {schema: {'x-ts-type': Character}}},
},
},
})
async create(#requestBody() character: Character): Promise<Character> {
//add following lines
let characterId = 1;
while(await this.characterRepository.exists(characterId)){
characterId ++;
}
character.id = characterId;
//add above lines
return await this.characterRepository.create(character);
}
you probably already noticed the auto-increment id feature. When you call the post API multiple times (leave id blank), the id increased by 1 every time. This feature is supported by the in-memory database. But we are using MongoDB in this project. If we want to have that feature, we need to do that programmatically.
For more information follow below link
https://strongloop.com/strongblog/building-online-game-with-loopback-4-pt1/
see the section just above the API Explorer heading
or find for 'auto increment id' you will be taken to that paragraph
Hopefully, this helps, write me if there is any other query.
Thanks
I'm also playing with Mongo and it can autogenerate your id for you.
Specifically, when you create your model, using lb4 model, choosing 'Entity' and then you're prompted:
Let's add a property to Participant
Enter an empty property name when done
? Enter the property name: id
? Property type: string
? Is id the ID property? Yes
? Is id generated automatically? Yes
This will generate your model with the property:
#property({
type: 'string',
id: true,
generated: true,
})
id?: string;
Great.. then when creating your CRUD controller:
? What kind of controller would you like to generate? REST Controller with CRUD functions
? What is the name of the model to use with this CRUD repository? Person
? What is the name of your CRUD repository? PersonRepository
? What is the name of ID property? id
? What is the type of your ID? string
? Is the id omitted when creating a new instance? Yes
? What is the base HTTP path name of the CRUD operations? /persons
Now when hitting your endpoint, the create POST doesn't take an ID, but will return one for you.
You can do something like in this example
let last_record = await this.testRepository.findOne({order: ['id DESC']});
if(last_record) invoice.id = last_record.id+1;
This will generate your model with the property:
#property({
type: 'number',
id: true,
default: 1,
generated: false
})
id: number;
Hopefully, this helps, please write me if there is any other code. Thanks
This class inherits from the DefaultCrudRepository class and overrides the create method. The method uses the "Counters" collection to hold the last id of the current data class (this.entityClass.name). The findAndModify method will prevent duplicate id values from being created.
import {DefaultCrudRepository, Entity, DataObject, Options} from '#loopback/repository';
export class MongoAutoIncIdRepository<T extends Entity, ID, Relations extends object = {}> extends DefaultCrudRepository<T, ID, Relations> {
public async create(entity: DataObject<T>, options?: Options): Promise<T> {
if (!this.dataSource.connected) {
await this.dataSource.connect()
}
let mongoConnector = this.dataSource.connector!
let collection = mongoConnector.db.collection('Counters')
let result = await collection.findAndModify(
{
collection: this.entityClass.name
},
[['_id', 'asc']],
{
$inc: {value: 1}
},
{
upsert: true,
new: true
})
console.log(result)
// #ts-ignore
entity.id = result.value.value
return super.create(entity, options)
}
}
It's easy to use. Inherit your repository not from DefaultCrudRepository, but from MongoAutoIncIdRepository if auto increment is required. Then, when the create method is called, the id will increase by 1 automatically.

Model validation isUUID not working

I am currently trying to implement usage of UUID as s primary key for my user model in SailsJS application, using MongoDB. As for now the primary key is generated by other system, I would like to validate if uuid attribute is valid UUID.
Validation isEmail is working fine for me, but isUUID accepts string like "john-doe" so it looks like it is not working.
My configuration looks like this:
module.exports = {
primaryKey: 'uuid',
dontUseObjectIds: true,
attributes: {
uuid: {
type: 'string',
isUUID: true,
columnName: '_id',
required: true
},
...
}
}
My only thought is that the validaiton does not work against primary key attribute.
Any ideas what else might be wrong? Thanks

Manually insert into Heroku PostgreSQL

I want to add some records in a table on the PostgreSQL db that Heroku offers. I am using Sequelize as ORM.
The query would be this one:
INSERT INTO "Categories" (name) VALUES ('Familie'), ('Liefde'), ('Tienertijd'), ('Kindertijd'), ('Hobbies');
However, I get this error that says I should also specify two more columns that are automatically created by Sequelize, namely createdAt and updatedAt.
ERROR: null value in column "createdAt" violates not-null constraint
DETAIL: Failing row contains (1, Familie, null, null).
How can I manually add these records, without going through Sequelize?
EDIT: this is the Sequelize model for Categories:
module.exports = (sequelize, DataTypes) =>
sequelize.define('Category', {
name: {
type: DataTypes.STRING,
unique: true
}
})
Since I didn't really need the timestamps, I realized you can specify not to use them as shown in the following snippet:
sequelize.define('Category', {
name: { type: DataTypes.STRING , unique: true},
}, {
timestamps: false
});
This way I don't need to specify the createdAt and updatedAt values when doing an INSERT.

Sails.js associations populate with different connections

I have two models
countries - from mysql server
Country = {
tableName: 'countries',
connection: 'someMysqlServer',
schema: true,
migrate: 'safe',
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
country_id: {
type: 'integer',
primaryKey: true,
autoIncrement: true
},
....
}
};
User = {
connection: 'somePostgresqlServer',
attributes: {
id: {
type: 'integer',
primaryKey: true,
autoIncrement: true
},
country_id: {
model: 'country'
},
$> User.findOneById(1).populate('country_id').exec(console.log)
and get error
sails> Error (E_UNKNOWN) :: Encountered an unexpected error
: Unable to determine primary key for collection `countries` because an error was encountered acquiring the collection definition:
[TypeError: Cannot read property 'definition' of undefined]
at _getPK (/projects/foturist-server/node_modules/sails-postgresql/lib/adapter.js:923:13)
at StrategyPlanner.__FIND__.Cursor.$getPK (/projects/foturist-server/node_modules/sails-postgresql/lib/adapter.js:504:20)
.....
Details: Error: Unable to determine primary key for collection `countries` because an error was encountered acquiring the collection definition:
[TypeError: Cannot read property 'definition' of undefined]
Why country association uses with postgre-connection ?
Well, since the two models are on different database connections, you're not going to be able to do an actual SQL join. I would think what you'd need is a
User.find({id: 1}).exec(function(user) {
var theUser = user;
Country.find(user.country_id)
.exec(function(country) {
theUser.country = country;
return theUser;
}); });
I'm not sure what specific needs you're trying to address, but since a lookup table of countries is unlikely to frequently change, and is in an entirely different data store, I would suggest caching this data in something like Redis or Memcache. Then on your User find callback you can fetch the country by id from your cache store. This will be much faster unless you expect this data to change on a regular basis. You could write a service that does a lazy lookup in your other database and serves from the cache then on, or cache them all up front when your app launches.