Add object with relation to database using sequelize - javascript

I'm trying to add an object with a related object to the sequelize database but I can't figure out how to do it properly. I've read the documentation but I don't seem to have the methods on my objects they're using.
My model looks like this:
Client = db.define('Client', {
name: Seq.STRING,
street1: Seq.STRING,
street2: Seq.STRING,
zip: Seq.STRING(7),
city: Seq.STRING,
short: { type: Seq.STRING(10), unique: true, allowNull: true }
});
TrackedTime = db.define('TrackedTime', {
start: Seq.DATE,
end: Seq.DATE,
title: Seq.STRING,
description: Seq.TEXT
});
Client.hasMany(TrackedTime);
Client.sync();
TrackedTime.sync();
db.sync();
First I search for the client using arguments read from commandline args (this works):
Clients.findAll({ where: { name: arg }}).then(function (clients) {
startTimeTrack(clients, argv.t, argv.d, start);
});
And finally, the method that does not work as I've expected when I read the docs is this one:
function startTimeTrack(client, title, description, start) {
if (typeof client === 'undefined' || client === null)
throw "Please specify a client to track the time for!";
if (typeof title === 'undefined' || title === null)
throw "You need to specify a title!";
description = typeof description !== 'undefined' ? description : null;
start = typeof start !== 'undefined' ? start : new Date();
if (!(start instanceof Date))
throw "This is not a valid Date";
console.log('\nClient object:\n', JSON.stringify(client, null, 2));
TrackedTime.create({
start: start,
end: null,
title: title,
description: description
}).then(function (tt) {
console.log('\nTrackedTime object: \n' + JSON.stringify(tt, null, 2));
tt.setClient(client); // exception here!
});
}
The exception I get is this one:
Unhandled rejection TypeError: undefined is not a function
at startTimeTrack (C:\Users\admin\dev\tim\bin\cmd.js:255:5)
at C:\Users\admin\dev\tim\bin\cmd.js:221:6
at null.<anonymous> (C:\Users\admin\dev\tim\bin\cmd.js:285:4)
at tryCatcher (C:\Users\admin\dev\tim\node_modules\sequelize\node_modules\bluebird\js\main\util.js:26:23)
at Promise._settlePromiseFromHandler (C:\Users\admin\dev\tim\node_modules\sequelize\node_modules\bluebird\js\main\pr
omise.js:503:31)
at Promise._settlePromiseAt (C:\Users\admin\dev\tim\node_modules\sequelize\node_modules\bluebird\js\main\promise.js:
577:18)
at Promise._settlePromises (C:\Users\admin\dev\tim\node_modules\sequelize\node_modules\bluebird\js\main\promise.js:6
93:14)
at Async._drainQueue (C:\Users\admin\dev\tim\node_modules\sequelize\node_modules\bluebird\js\main\async.js:123:16)
at Async._drainQueues (C:\Users\admin\dev\tim\node_modules\sequelize\node_modules\bluebird\js\main\async.js:133:10)
at Immediate.Async.drainQueues [as _onImmediate] (C:\Users\admin\dev\tim\node_modules\sequelize\node_modules\bluebir
d\js\main\async.js:15:14)
at processImmediate [as _immediateCallback] (timers.js:367:17)
I really don't know what I'm doing wrong here. The documentation did it like I did it here. I also tried multiple variations of that set-method (setClients, addClient).
How do I properly add related objects to the database using sequelize?
Edit:
This is the client object I'm receiving from the database:
Client object:
{
"id": 3,
"name": "Name Surname",
"street1": "Street 15",
"street2": "",
"zip": "12345",
"city": "City",
"short": "ms",
"createdAt": "2015-09-04T13:48:18.980Z",
"updatedAt": "2015-09-04T13:48:18.980Z"
}
Notice: I moved on with this small (and private) project and I'm just using node-sqlite3 to handle my 4 tables manually. If you, who landed here, have the same problem and one of the answers helped you, give me a hint and I'll accept it as answer.

FindAll will return array of clients, so if you want to return just one client you should use findOne.
Then according with Sequelize Associations docs , you could use createAssociation , in your case (not tested) :
function startTimeTrack(client, title, description, start) {
//....
//console.log(client.createTrackedTime) --> must return function
client.createTrackedTime({
start: start,
end: null,
title: title,
description: description
})
.then(function (tt) {
console.log(tt.get({plain:true}));
})
.catch(function (error){
console.log(error)
});
}

Related

meteor How to use upsert | Exception while simulating the effect of invoking ” TypeError: Cannot read properties of undefined (reading ‘_id’) react.js

I’m having trouble with upsert with meteor.js. I could update questions finely with the below codes but I won’t be able to insert new data.
file in client side
const onSave = () =>{
// there is more codes but omitted
questions.forEach(question => {
Meteor.call('modifyQuestion', question);
})
}
file in server side (collection file)
modifyQuestion(question) {
check(question, Object);
const questionId = Measures.findOne({questionId: question._id});
Measures.upsert(
{_id: questionId._id},
{
$set: {
title: question.text,
},
},
);
},
Got error saying…
Exception while simulating the effect of invoking 'modifyQuestion' TypeError: Cannot read properties of undefined (reading '_id')
I thought when {_id: questionId._id} got undefined, that’s the time upsert understand that there is no matching data found and insert one as new data into the database.
Is this wrong?
I switched $set to $setOnInsert, but still didn't work...
ADDED
Now I don't see any error but i couldn't insert new data. I could update data tho.
modifyQuestion(question) {
check(question, Object);
Measures.upsert(
{questionId: question._id}, // changed
{
$set: {
title: question.text,
},
$setOnInsert: {type: 'multipleChoice'}
},
);
},
Also removed const questionId = Measures..... part
You still need to set the questionId on insert:
modifyQuestion(question) {
check(question, Object);
Measures.upsert(
{ questionId: question._id },
{
$set: {
title: question.text,
},
$setOnInsert: {
questionId: question._id
type: 'multipleChoice'
}
},
);
},
Otherwise there will never be a doc that contains the questionId.
Note: Another helpful tool would be Collection2 and define a schema, so it throws errors, in case docs are inserted/updated that violate a schema. Using this would have thrown, that questionId is missing on insert.

Using RX with yeoman generator

I want to use RXJS with typescript yeoman generator, according to the docs inquirer which is the engine under yeoman support RXJS
https://github.com/SBoudrias/Inquirer.js/#reactive-interface
I use the following
export default class myGenerator extends Generator {
...
async prompting() {
const prompts = new Subject<Generator.Question>();
await this.prompt(prompts);
prompts.next({
name: "appName",
message: "app name: ",
type: "input",
default: this.props!.appName,
validate(input: string) {
const appName = validateAppName(input);
return !appName[1] ? appName[0] : true;
},
});
prompts.next({
type: "list",
name: "tech",
message: "Which type",
default: "CLI",
choices: [{ name: "CLI" }, { name: "CloudApp" }],
});
prompts.complete();
}
Now while running it I got error :
Error: You must provide a `name` parameter
at InputPrompt.throwParamError (/usr/local/lib/node_modules/yo/node_modules/inquirer/lib/prompts/base.js:73:11)
at new Prompt (/usr/local/lib/node_modules/yo/node_modules/inquirer/lib/prompts/base.js:33:12)
at new InputPrompt (/usr/local/lib/node_modules/yo/node_modules/inquirer/lib/prompts/input.js:11:1)
at PromptUI.fetchAnswer (/usr/local/lib/node_modules/yo/node_modules/inquirer/lib/ui/prompt.js:85:25)
at MergeMapSubscriber._tryNext (/usr/local/lib/node_modules/yo/node_modules/rxjs/internal/operators/mergeMap.js:69:27)
at MergeMapSubscriber._next (/usr/local/lib/node_modules/yo/node_modules/rxjs/internal/operators/mergeMap.js:59:18)
at MergeMapSubscriber.Subscriber.next (/usr/local/lib/node_modules/yo/node_modules/rxjs/internal/Subscriber.js:66:18)
at MergeMapSubscriber.notifyNext (/usr/local/lib/node_modules/yo/node_modules/rxjs/internal/operators/mergeMap.js:95:26)
at InnerSubscriber._next (/usr/local/lib/node_modules/yo/node_modules/rxjs/internal/InnerSubscriber.js:28:21)
at InnerSubscriber.Subscriber.next (/usr/local/lib/node_modules/yo/node_modules/rxjs/internal/Subscriber.js:66:18)
events.js:170
throw er; // Unhandled 'error' event
Im not sure where to put the name as all the prompts are providing the name property. , any idea ?
What I need is to create just two simple questions which will work with RXJS
How I can do that ?

Error Handling: E11000 duplicate key error collection

I am having a problem with the user model that I'm using with Mongoose and MongoDB to create each profile in my database. It works fine to post one user, but throws the following error if I logout and try again:
{
"name": "MongoError",
"message": "E11000 duplicate key error collection: CourtAPIDev.users index: trackers.case_id_1 dup key: { : null }",
"driver": true,
"index": 0,
"code": 11000,
"errmsg": "E11000 duplicate key error collection: CourtAPIDev.users index: trackers.case_id_1 dup key: { : null }"
}
According to mongoose documentation: If there is more than one document (a second user) without a value for the indexed field or is missing the indexed field, the index build will fail with a duplicate key error. I don't know how to set this _id property for the trackers property –– I thought it generated automatically!
Here's the trackers part of my Schema. And the relevant case_id property, which seems to be throwing the "null" error.
The whole repository can be found on my Github here, but the likely problem spots are the ones I highlighted, I think. Here's the github link: https://github.com/KingOfCramers/node_login_with_trackers
user model:
const UserSchema = new mongoose.Schema({
email: {
type: String,
required: true,
trim: true,
minLength: 1,
unique: true,
validate: {
validator: (value) => {
return validator.isEmail(value);
},
message: '{VALUE} is not a valid email'
}
},
password: {
type: String,
required: true,
minlength: 6
},
tokens: [{
access: {
type: String,
required: true
},
token: {
type: String,
required: true
}
}],
trackers: {
tweets: [TwitterSchema],
legislation: [LegislationSchema],
court_cases: [CourtCaseSchema]
},
frequency: [EmailSchema]
});
Express route:
app.post("/users", (req,res) => {
var body = _.pick(req.body, ['email', 'password']);
body.frequency = {
alert_time: new Date(),
email: req.body.email
}
var user = new User(body);
user.save().then(() => {
return user.generateAuthToken();
}).then((token) => {
res.header("x-auth", token);
res.send(user);
}).catch((e) => {
res.status(400).send(e);
});
});
Test (mocha):
it("Should post a new user", (done) => {
var email = "uniqueemail#example.com"
var password = "9webipasd"
supertest(app)
.post("/users") // Post request to the /todos URL
.send({
email,
password
})
.expect(200)
.expect((res) => {
expect(res.headers).toIncludeKey('x-auth')
expect(res.body._id).toExist();
expect(res.body.email).toBe(email);
})
.end((err) => {
if(err){
return done(err);
}
User.findOne({email}).then((user) => {
expect(user).toExist();
expect(user.password).toNotBe(password);
done();
}).catch((e) => done(e));
});
});
My guess is that there is an index on CourtCaseSchema.case_id which does not allow duplicates.
I think you could check (in a mongo shell) that with CourtAPIDev.court_cases.getIndexes() (I think your db is named CourtAPIDev and the collection is named court_cases but I am not sure about that).
Also if you clean the test db after each run, that would explain why the tests are passing, since there is no more than one user.
Turns out, it was to do with my mongodb database, not any of my code. After searching around online, I found that if I logged into the mongo shell and then dropped all indexes from the users collection, it solved my problem. Could someone explain why this was causing my program to crash? I think it may have to do with an old user model, but I don't really understand. Thanks!
Even if you have all of your keys as unique=False, you may still get E11000 duplicate key error. So in that case, just follow these steps and check if your error is resolved.
Delete all documents from the collection (e.g. db.collection_name.deleteMany({}))
Drop the COLLECTION (NOT THE DATABASE) (e.g db.collection_name.drop())
Cheers !!

Invalid callback() argument error with Mongoose

I have a collection like this (very simplified)...
var parentSchema = new mongoose.Schema({
firstName: String,
mobile: String
});
var familySchema = new mongoose.Schema({
groupId: { type: mongoose.Schema.Types.ObjectId, index: true },
parents: [parentSchema]
});
For a given group, I'd like to find all of the parents of families in that group who have a mobile value set (exists), and unset those mobile values.
I've been able to piece this much together by looking at other examples...
Family.update(
{ groupId: someGroupId, "parents.mobile": {"$exists":"true"} },
{ $unset : { "parents.$.mobile" : 1 } }, false, true
).then(function() {
// do other stuff
});
Running generates the error:
Trace: [Error: Invalid callback() argument.]
I've tried several variations, but this one seems the most correct to me.
The .update() signature for mongoose models is:
Model.update(<{query}>,<{update}>,[<{options}>],[callback])
So when using promises, it's just the first two with the optional "third" options. The "fourth" would be a callback function, and hence the error:
Family.update(
{ "groupId": someGroupId, "parents.mobile": {"$exists": true } },
{ "$unset": { "parents.$.mobile" : "" } },
{ "multi": true }
).then(function() {
Too many people read the "shell" signature, even though the usage of:
.update(<{query}>,<{update}>,<upsert>,<multi>)
Has been deprecated in favour of the standard "options" arrangement for some time.
Always refer to the method that actually applies to your language API.

loopback upsert with allowExtendedOperators

I'm trying to do an upsert where I $push a new element onto a field that is an array.
However, whenever I use $push I get the error telling me that I'm not allowed to use $ at the beginning of operators.
Here's the debug trace:
loopback:connector:mongodb create +3s ThingUser { user: 'gerald', '$push': { things: 'hats' } }
loopback:connector:mongodb MongoDB: model=ThingUser command=insert +2ms [ { user: 'gerald', '$push': { things: 'hats' }, _id: undefined },
{ safe: true },
[Function] ]
loopback:connector:mongodb Error: +5ms { [MongoError: key $push must not start with '$']
name: 'MongoError',
message: 'key $push must not start with \'$\'' }
loopback:connector:mongodb create.callback +0ms ThingUser { [MongoError: key $push must not start with '$']
name: 'MongoError',
message: 'key $push must not start with \'$\'' } null
It seems as though I'm not putting allowExtendedOperators in the correct place. I have tried everywhere where does this thing go? Can it not work with upsert?

Categories