Make a model a collection of itself - javascript

The title may not be clear, but what I want to achieve is to have Categories with parentCategories. For example:
/-Clothes
/---Men
/---Women
/---Kids
/-----Newborns
So I thought I could make every category have an optional parent category and whenever I add a category with a parent one, find this parent category and add the new subCategory to it as well. Am I clear?
This is what I've done so far:
Category.js (Model)
module.exports = {
connection: 'MongoDB',
attributes: {
name: {
type: 'string',
required: true,
unique: true
},
description: {
type: 'string'
},
products: {
collection: 'product',
via: 'category'
},
parentCategory: {
model: 'category'
},
subCategories: {
collection: 'category',
via: 'parentCategory'
},
addSubCategory: function(sc) {
this.subCategories.push(sc);
}
}
};
It doesnt seem to be working. I'm calling addSubCategory from my controller, sc and this values are correct, but it never adds the "subCategory" attribute to the category. I know this may not be the best approach, any suggestions?

You don't need subCategories attribute. Following design would be my suggestion.
module.exports = {
connection: 'MongoDB',
attributes: {
name: {
type: 'string',
required: true,
unique: true
},
type: {
type: 'string',
enum: ['parent', 'subcategory'],
},
description: {
type: 'string'
},
products: {
collection: 'product',
via: 'category'
},
parentCategory: {
model: 'category' // this exists only if type is 'subcategory' else null
},
addSubCategory: function(sc) {
this.subCategories.push(sc);
}
}
};
Let me know if you have any doubt.

Related

Are nullable foreign keys possible with objectionjs/knex?

Maybe this is a simple fix, but I can't seem to figure out what I'm doing wrong here.
I have a table that lists all the states
Model:
static get jsonSchema() {
return {
type: 'object',
properties: {
id: { type: 'integer' },
name: { type: 'string', minLength: 1, maxLength: 100 },
},
}
}
static get relationMappings() {
return {
users: {
relation: Model.HasManyRelation,
modelClass: User,
join: {
from: `${tableNames.state}.id`,
to: `${tableNames.user}.state_id`,
},
},
}
Migration:
await knex.schema.createTable(tableNames.state, (table) => {
table.increments().primary().notNullable()
table.string('name', 100).notNullable()
User table model:
static get jsonSchema() {
return {
type: 'object',
properties: {
id: { type: 'integer' },
first_name: { type: 'string', minLength: 1, maxLength: 100 },
last_name: { type: 'string', minLength: 1, maxLength: 100 },
state_id: { type: 'integer', default: null },
},
}
}
static get relationMappings() {
return {
state: {
relation: Model.BelongsToOneRelation,
modelClass: State,
join: {
from: `${tableNames.user}.state_id`,
to: `${tableNames.state}.id`,
},
}
}
}
User table migration:
await knex.schema
.createTable(tableNames.user, (table) => {
table.increments().primary().notNullable()
table.string('first_name', 100).notNullable()
table.string('last_name', 100).notNullable()
table.integer('state_id').unsigned()
table
.foreign('state_id')
.references('id')
.inTable(tableNames.state)
.onDelete('SET NULL')
})
Now the issue: I want the state_id column to be nullable, as in not every user will have a state assigned to them. But when I try inserting a user with no state_id, I get this: insert or update on table \"user\" violates foreign key constraint \"user_state_id_foreign\".
two things you are doing wrong
in your json schema define your column as state_id: {type: ['integer', 'null']}
in your user migrations make table.integer('state_id').unsigned().nullable()

Sails.js: save() model doesn't seems to work Error (E_UNKNOWN)

My model definition looks like this:
//api/models/Table.js
module.exports = {
tableName: 'table',
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
id: {
type: 'integer',
autoIncrement: true,
primaryKey: true,
size: 11
},
title1: {
type: 'string',
index: true,
size: 255
},
title2: {
type: 'string',
size: 255
},
title2: {
type: 'string',
size: 255
},
countries: { //Countries nationalities
model: 'hg_laender'
},
year: {
type: 'string',
size: 4
},
relased: { //released
type: 'string',
enum: ['true', 'false']
},
createdOn: { //Created on
type: 'datetime'
},
changedOn: { // Changed on
type: 'datetime'
},
documents: { //Document type
collection: 'documents',
via: 'table',
dominant: true
},
creator: { //Creator
collection: 'creator',
via: 'table',
dominant: true
},
kanton: { // Canton
collection: 'kanton',
via: 'table',
dominant: true
},
language: {
collection: 'language',
via: 'table',
dominant: true
}
}
};
The code generating the error is the following
Table.find()
.exec((err, tables) => {
if(err) {
sails.log.error('first error', err);
}
sails.log.debug(tables[0]); //The record is loaded correctly
tables[0].save((err, model) => {
if(err) {
sails.log.error('second error', err);
}
});
});
I get the following error message:
error: second error Error (E_UNKNOWN) :: Encountered an unexpected error
at new WLError (/home/xxx/node_modules/waterline/lib/waterline/error/WLError.js:25:15)
at /home/xxx/node_modules/waterline/lib/waterline/model/lib/defaultMethods/save.js:196:17
at /home/xxx/node_modules/async/lib/async.js:52:16
at /home/xxx/node_modules/async/lib/async.js:550:17
at /home/xxx/node_modules/async/lib/async.js:544:17
at _arrayEach (/home/xxx/node_modules/async/lib/async.js:85:13)
at Immediate.taskComplete (/home/xxx/node_modules/async/lib/async.js:543:13)
at processImmediate [as _immediateCallback] (timers.js:383:17)
If a use the create() method it works. t actually save the record on the database. But if I try to update it, it doesn't work.
Any idea of what I'm doing wrong?
Additional info:
- sails.js version: 0.12.8
Seems like there was a problem if a manually specify the id of the model.
Now i changed the model like below and it works. Btw I don't know why specifing the id will not work. Also it' doesn't throw any error when creating a model..
//api/models/Table.js
module.exports = {
tableName: 'table',
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
//id: {
// type: 'integer',
// autoIncrement: true,
// primaryKey: true,
// size: 11
//},
title1: {
type: 'string',
index: true,
size: 255
},
title2: {
type: 'string',
size: 255
},
title2: {
type: 'string',
size: 255
},
countries: { //Countries nationalities
model: 'hg_laender'
},
year: {
type: 'string',
size: 4
},
relased: { //released
type: 'string',
enum: ['true', 'false']
},
createdOn: { //Created on
type: 'datetime'
},
changedOn: { // Changed on
type: 'datetime'
},
documents: { //Document type
collection: 'documents',
via: 'table',
dominant: true
},
creator: { //Creator
collection: 'creator',
via: 'table',
dominant: true
},
kanton: { // Canton
collection: 'kanton',
via: 'table',
dominant: true
},
language: {
collection: 'language',
via: 'table',
dominant: true
}
}
};
I too faced this Issue while using Sails with mongo. I fixed this by changing "id" attribute to some other attribute, say "Id". While creating a record, an "id" attribute is created itself that holds mongo ObjectId. May be this could be the reason for not allowing two id attribute at the same time resulting into error.

How to create a list of objects which are one-way associated with objects of another model in SailsJS?

I have models Playlist.js and User.js. I want to have a list of users in Playlist who can answer for the comments on them. I do not want the attribute to appear in User. (i.e. one-way-association)
Playlist.js
module.exports = {
attributes: {
id: {
type: 'integer',
autoIncrement: true,
primaryKey:
},
name: {
type: 'string',
size: 128,
required: true
},
// many to many relationship with role
roles_with_access: {
collection: 'role',
via: 'playlist',
through: 'rolehasplaylist'
},
// THIS ATTRIBUTE ASSOCIATE WITH ONE USER
// BUT INSTEAD OF THAT I WANT A LIST OF USERS
users_who_can_answer_comments: {
model: 'user'
}
}
};
User.js
module.exports = {
attributes: {
id: {
type: 'integer',
autoIncrement: true,
primaryKey: true,
},
name: {
type: 'string',
size: 128,
required: true
},
email: {
type: 'email',
required: true,
unique: true
},
adminRole: {
model: 'role'
}
}
};
Sails documentation have mentioned one-way association only for one-to-one mapping - http://sailsjs.org/documentation/concepts/models-and-orm/associations/one-way-association
I want to find a way to have a list of users with associations to users?
Change model to collection:
users_who_can_answer_comments: {
collection: 'user'
}

Upsert: Unable to invalidate a subdocument that has not been added to an array

I have an upsert query in mongoose which was working in 3.8 but, after I've upgraded to 4 I'm getting
Unable to invalidate a subdocument that has not been added to an array
this is my model:
var ActivitySchema = new Schema({
owner:{
type: Schema.Types.ObjectId,
ref: 'User'
},
sequence:{
type:Number,
default: 0
},
items:[
{
posted:{
type:Date,
default:Date.now
},
verb:{
type: String,
enum: [ 'leave','join','support','share','comment', 'upload', 'rate','message','update', 'signup']
},
text:{
type: String,
},
reference: {
objectType:{
type: String,
enum: [ 'document','element','process', 'project', 'user']
},
refObj:{}
}
}]
});
the upsert:
Activity.update({
$and:[
{'owner':ownerId},
{'sequence':bucket}
]},
{
$push:{items:newItem }
},
{
upsert:true
}).execAsync();
and the data is like this:
//newItem
{ verb: 'join',
text: 'Has joined to a team',
reference:
{
refObj: { teamId: '56269fd1e923cc7a7b46dcf8', name: 'test1' },
objectType: 'user'
}
}
ownerId is a mongoId like 56251c01507dc35423694118
and bucket is an integer 0
is there any breacking change that I need to be aware?, I've been looking and I haven't found yet related, any other workaround, solution?
I had encountered the same problem, if it is the same case then make sure all fields type are matched to the mongoose.model('yourModel').
Hopes that helps.

meteor: add some value to nested documents

I'm trying to add a value to a nested schema:
groups = new SimpleSchema({
title: { type: String, optional: true },
element: { type: [elements], optional: true }
});
elements = new SimpleSchema({
description:{ type: String, optional: true },
anything: { type: String, optional: true }
});
MongoDB.attachSchema(new SimpleSchema({
title: { type: String },
slug: { type: String, unique: true },
language: { type: String, defaultValue: "en" },
group: { type: [groups], optional: true },
}));
Now I want to add just a new element-description to an existing entry in the DB. I tried this, but it doesn't work.
Uncaught Error: When the modifier option is true, validation object must have at least one operator
var newElement = {
description: 'insert this as a new element description'
};
MongoDB.update({ _id: Id }, { $push: { 'group.element': newElement }}, function(error) { if(error) console.warn(error); });
Is it correct to use 'group.element' as a $push-parameter?
Update
I forgot the index of group: $push: { 'group.0.element': newElement }
Also I have to define elements before groups in the schema.

Categories