Are nullable foreign keys possible with objectionjs/knex? - javascript

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()

Related

Mongoose/Mongodb: Index Already Exists With Different Options

I am using Mongoose 5.1.7 and attempting to create a compound index across multiple text indexes in my defined schema. Here is my schema definition:
const mongoose = require('mongoose');
const alumniSchema = mongoose.Schema({
firstName: {
type: [String],
required: true
},
lastName: {
type: [String],
required: true
},
classYear: {
type: Number,
required: true
},
photoURL: {
type: String,
},
education: [
{
school: {
type: String,
required: true
},
gradYear: {
type: Number,
required: true
},
degreeType: String,
degreeSubject: String,
}
],
jobs: [
{
employer: {
type: String,
required: true
},
position: String,
startDate: Date,
endDate: Date,
isCurrent: Boolean
}
],
contactInfo: {
phoneNumber: {
type: String,
},
email: {
type: String,
}
},
})
alumniSchema.index({ firstName: 'text', lastName : 'text', email: 'text' });
module.exports = mongoose.model('Alumni', alumniSchema);
When I boot up the server, I receive the following error:
MongoError: Index: { v: 2, key: { _fts: "text", _ftsx: 1 }, name: "firstName_text_lastName_text_email_text", ns: "5b3be578c0c6e317f7c1bc2b_test.alumnis", background: true, weights: { email: 1, firstName: 1, lastName: 1 }, default_language: "english", language_override: "language", textIndexVersion: 3 } already exists with different options: { v: 2, key: { _fts: "text", _ftsx: 1 }, name: "firstName_text_lastName_text_classYear_text_education.school_text", background: true, weights: { classYear: 1, education.school: 1, firstName: 1, lastName: 1 }, default_language: "english", language_override: "language", ns: "5b3be578c0c6e317f7c1bc2b_test.alumnis", textIndexVersion: 3 }
I have been messing around with this for a while and evidently previously created an index. When I use the mongo shell to check the indexes that I currently have set up, however, I cannot find the index "firstName_text_lastName_text_classYear_text_education.school_text" referenced by the error message:
> db
test
> db.collection.getIndexes()
[ ]
I am at an impasse--I'm not sure if I've incorrectly created the index, or if I am supposed to drop the index (it doesn't look like Mongoose natively supports a dropIndex() function).
Has anyone else dealt with this issue? Thanks!
Looks like Mongoose dynamically creates the index at runtime. The trick for me was adding:
var Alumni = mongoose.model('Alumni', alumniSchema);
Alumni.collection.dropIndex('firstName_text_lastName_text_classYear_text_education.school_text', function(err, result) {
if (err) {
console.log('Error dropping index!', err);
}
});
and then restarting the server.
THEN I was able to change the index to whatever I wanted. Note that I still needed to add the above code segment and restart the server every time I wanted to update the index.

Only Index the fields that are present in mappings - ElasticSearch v5.2.2

While creating mapping for mine type type1 i have declared 3 fields,
But while indexing the data, the body can have many other fields too that are not present in mine mapping
esClient.indices.putMapping({
index: 'index1',
type: 'type1',
body: {
properties: {
Name: {
type: 'string',
},
Description: {
type: 'string',
},
Address: {
type: 'string',
},
}
}
})
Here, the data object have two more fields class and organization, ElasticSearch will by default create the types for the extra fields that are not mentioned in mine mappings.
const data = {
Name: 'pauline',
Description: 'he\'s pauline from academy',
Address: 'avenue street',
class: 'Standard form 1', // ignore this while indexing
organization: 'Escalar Communications' // ignore this while indexing
}
So, Is there a way to only index the fields data that are present in the _mappings and exclude the others, I mean some options to set.
OR I have to do it mineself
esClient.index({
index: 'index1',
type: 'type1',
body: data,
}, (error, response) => {
console.log(error, response);
});
Yes you can do it by adding "dynamic": false to your mapping to ignore fields that are not in your mapping. By default it is true.
esClient.indices.putMapping({
index: 'index1',
type: 'type1',
body: {
dynamic: false, <--- add this
properties: {
Name: {
type: 'string',
},
Description: {
type: 'string',
},
Address: {
type: 'string',
},
}
}
})

How to do mutation on array in Relay?

I want to use mutation in Relay to change an array (not connection). The array is typed GraphQLList in the GraphQL side. The graphql side worked perfectly, but relay side needs dataID for each item in an array. And when I am inserting new item or modifying existing item in the array, there are no dataID provided? What is the right way to do this? By the way, I am using redux to maintain the list, and submit changes via relay at the end.
The schema:
let widgetType = new GraphQLInputObjectType({
name: 'Widget',
fields: () => ({
label: {
type: GraphQLString
},
type: {
type: GraphQLString
},
list: {
type: new GraphQLList(GraphQLString)
},
description: {
type: GraphQLString
},
required: {
type: GraphQLBoolean
}
})
});
let modifyFormMutation = mutationWithClientMutationId({
name: 'ModifyForm',
inputFields: {
id: {
type: new GraphQLNonNull(GraphQLString)
},
name: {
type: new GraphQLNonNull(GraphQLString)
},
userId: {
type: new GraphQLNonNull(GraphQLString)
},
widgets: {
type: new GraphQLList(widgetType)
}
},
outputFields: {
formEdge: {
type: formConnection.edgeType,
resolve: (obj) => {
return {
node: {
id: obj.id,
name: obj.name,
userId: obj.userId,
widgets: obj.widgets
},
cursor: obj.id
};
}
},
app: {
type: appType,
resolve: () => app
}
},
mutateAndGetPayload: ({
id, name, userId, widgets
}) => {
db.collection('forms').findOneAndUpdate({
_id: new ObjectID(id)
}, {
name, userId, widgets, createAt: Date.now()
});
return {
id, name, userId, widgets
};
}
})
Relay mutation:
export default class ModifyFormMutation extends Mutation {
getMutation () {
return Relay.QL`mutation{modifyForm}`;
}
getFatQuery() {
return Relay.QL`
fragment on ModifyFormPayload {
formEdge
app { forms }
}
`;
}
getCollisionKey() {
return `check_${this.props.app.id}`;
}
getConfigs() {
return [{
type: 'FIELDS_CHANGE',
fieldIDs: {
formEdge: {node: this.props.node},
app: this.props.app.id
}
}];
}
getVariables() {
return {
name: this.props.node.name,
id: this.props.node.id,
userId: this.props.node.userId,
widgets: this.props.node.widgets
};
}
getOptimisticResponse() {
return {
formEdge: {
name: this.props.node.name,
id: this.props.node.id,
userId: this.props.node.userId,
widgets: this.props.node.widgets
}
};
}
}
And error message from browser:
"Variable "$input_0" got invalid value
{"name":"asdfasdfsa","id":"57e790cec252f32aa805e38d","userId":"57e10a02da7e1116c0906e40","widgets":[{"dataID":"client:618507132","label":"sdfas","type":"text","list":[],"description":"","required":true},{"label":"sfasdfasaaa","list":[],"type":"number","description":"","required":"false"}],"clientMutationId":"0"}.↵In
field "widgets": In element #0: In field "dataID": Unknown field."

Make a model a collection of itself

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.

Meteor: Add subdocument to existing record

I have the following Scheme:
dGroup = new SimpleSchema({
title: { type: String, optional: true },
element: { type: String, optional: true }
});
MongoDB.attachSchema(new SimpleSchema({
title: { type: String },
slug: { type: String, unique: true },
language: { type: String, defaultValue: "en" },
group: { type: [dGroup], optional: true },
}));
... and in the DB I got this:
{ "_id" : "ag9qXWpCYm87kZbEk", "title" : "Test", "slug" : "test", "language" : "en" }
Now I want to add a dGroup -> title:
updates['group.title'] = 'insert this as a new group title with no element';
MongoDB.update({ _id: Id }, { $push: updates }, function(error) { if(error) console.warn(error); });
But this doesn't work. So I need some help to add subdocuments in meteor in case they do not exist.
Try declaring your object first and push it properly, like this:
var newGroup = {
title: 'insert this as a new group title with no element'
};
MongoDB.update({ _id: Id }, { $push: {group: newGroup }}, function(error) { if(error) console.warn(error); });

Categories