Can't Delete Behaviour - javascript

I am having trouble with something that should be patently obvious. I cant seem to be able to delete properties of my object in node. This is in coffeescript, but I don't think that is relevant.
console.log doc
delete doc.password
console.log doc
Returns:
{ firstname: 'Andrew',
lastname: 'Plummer',
email: 'andrew#stackoverflow...',
password: 'blahblah',
_id: 5014c0a6af36bdaf03000001,
comments: [],
posts: [] }
{ firstname: 'Andrew',
lastname: 'Plummer',
email: 'andrew#stackoverflow...',
password: 'blahblah',
_id: 5014c0a6af36bdaf03000001,
comments: [],
posts: [] }
For something so seemingly obvious I have actually searched around stackoverflow and googled for about half an hour. Sorry if still i have missed a duplicate.

The answer as given by Frédéric in the comment ( so i cant mark it as true) is that my object needed to be explicitly turned into a new object as it had its delete disabled. This is the case with mongoose ODM models in node.

Related

Embedded Schema Inserting Blank in Meteor using Collection2

I am fairly new to meteor and attempting to insert to a collection using a model that uses embedded schemas. The content in the embedded schema is not being inserted into the db and is instead an empty entry.
The main model is being attached to the collection.
Guests = new Mongo.Collection('guests');
Schema = {}
Guests.attachSchema(new SimpleSchema({
BasicInformation : {
type: Schema.basicInfo,
optional: false,
},
})
The basicInfo schema is defined as follows.
Schema.basicInfo = new SimpleSchema({
firstName: {
type: String,
},
middleName: {
type: String,
},
lastName: {
type: String,
}
})
I am using this to insert in the collection on a common js file.
Guests.insert({
BasicInformation: {
firstName: 'First Name',
middleName: 'Middle Name',
lastName: 'Last Name'
},
})
If I remove the schema and add the fields in the main model instead of using an embedded schema, then it does get inserted. Not sure what’s up…help!
Welcome to Stack Overflow. And, as #Jankapunkt says, please put your code as formatted blocks in your question. Links to pictures hosted elsewhere may not work if the images get deleted. It's also easier for us to fix your code and show you what it should look like.
I think at the time you set up your schema, the Schema Object is empty. You add info to it later, but it's too late at that point. If you put the code in your question I can show you how, but I'm not willing to retype it for you.
UPDATE:
Good work. You need to populate the Schema object before you attach it to the table:
Guests = new Mongo.Collection('guests');
Schema = {} // Right now the object is empty
Schema.basicInfo = new SimpleSchema({ // So we add the sub-schema
firstName: {
type: String,
},
middleName: {
type: String,
},
lastName: {
type: String,
}
})
Guests.attachSchema(new SimpleSchema({
BasicInformation : {
type: Schema.basicInfo, // previously this was undef, now it is correct
optional: false,
},
})
That should work for you.

filter Sequelize belongsToMany get<Association> association table

I am working with Sequelize 4.37.10 and it works great.
Unfortunately the documentation is not perfect in my opinion. So it lacks a bit of describing the belongsToMany possibilities.
I have the following problem:
I defined my tables like this:
const Department = db.define('department', {
name: {type: Sequelize.STRING, allowNull: false},
shortName: {type: Sequelize.STRING, allowNull: false}
})
const Employee = db.define('employee', {
title: {type: Sequelize.STRING},
name: {type: Sequelize.STRING, allowNull: false},
surname: {type: Sequelize.STRING, allowNull: false},
.
.
role: {type: Sequelize.STRING}
})
Then I associated the tables like this:
const EmployeeDepartments = db.define('employeeDepartments', {
manager: {type: Sequelize.BOOLEAN, allowNull: false}
})
Department.belongsToMany(Employee, {through: EmployeeDepartments})
Employee.belongsToMany(Department, {through: EmployeeDepartments})
Now i want to get all department employees with the manager field set to true.
The creation was no problem, but the select is a problem for me.
I tried the following with no luck:
department.getEmployees({where: {manager: true}})
I also thought of scopes but I don't know how to design that properly.
Can you help me with that?
Funnily, I was just looking for the exact same thing, and the only result was your question from a few hours ago...
I solved it by now, what you need is the following:
department.getEmployees({ through: { where: { manager: true } } })
You can also get all employees of a department of which you only have the id:
const department = Department.build( { id: departmentId } );
// proceed as above
department.getEmployees({where: {manager: true}})
change this code with this.
department.getEmployees(
include:{
model: employeedepartments, // your employee departments model name
{where: {manager: true},
required:true,
}
})
You have to just add include in your query
I found a very simple answer myself after searching a while.
When using belongsToMany Sequelize does use a join to get data from the second table (I knew that).
I had the option to use the following syntax:
department.getEmployees({where: {'$employeeDepartments.manager$': true}})
I found that from a page on google but unfortunately I lost the url.
Maybe this helps someone with a similar problem.

Trying to understand the use of the populate method

I see that one way we use populate is to put one document from another collection into a "parent" collection. I was just going through this question and I was hoping someone could explain the answer to me better. And show me a practical use. Here is an example from the answer.
var PersonSchema = new mongoose.Schema({
t: String
}, {collection: 'persons'});
var User = mongoose.model('User', PersonSchema.extend({
_id: String,
name: String
}));
var ParentSchema = new mongoose.Schema({
s: String
}, {collection: 'parent'});
var Like = mongoose.model('Like', ParentSchema.extend({
_id: String,
user_id: {
type: String,
ref: 'User'
}
}));
Insert Data into DB,
var user = new User({
t: 't1',
_id: '1234567',
name: 'test'
});
var like = new Like({
s: 's1',
_id: '23456789',
});
user.save(function(err, u){
if(err)
console.log(err);
else {
like.user_id = u._id;
console.log(like);
like.save(function(err) {
if (err)
console.log(err);
else
console.log('save like and user....');
});
}
});
Query by
Like.findOne({}).populate('user_id').exec(function(err, doc) {
if (err)
console.log(err);
else
console.log(doc);
});
And the result is
{ _id: '23456789',
__t: 'Like',
user_id: { _id: '1234567', __t: 'User', t: 't1', name: 'test', __v: 0 },
s: 's1',
__v: 0 }
QUESTION
where does __t: 'User' come from?
I was thinking that using populate() or ref that would separate the collections but it looks like at the end the like collection has the users document in it. I think I wanted to use populate so I could make a document smaller.
3.Also if someone really wanted to help explain this to me I have an example that I have been trying to do and I don't know if I should use populate but if I should it would be great if you show me how. Here is the example.
You have
doctors
patients
information about the practice
There could be like a 1000 doctors and lots of patients for each doctor. and the information will be about their practice(like how many employees they have). so I feel that there should be a separation of concern.(one reason is to prevent a single document for a patient from getting to big). So If we're going with the populate method If you could explain how to set it up for this case. I guess I could have a doctor as a parent and a child refs for patients and another child refs for information about practice. so maybe there should be an array of objectId for the patients and an array for Other information
Q1: where does __t: 'User' come from?
Refer to this link.
mongoose now includes schema inheritance and discriminatorKey functionality that breaks mongoose-schema-extend. mongoose now sets the discriminatorKey schema option to __t by default
Q2: I was thinking that using populate() or ref that would separate the collections but it looks like at the end the like collection has the users document in it. I think I wanted to use populate so I could make a document smaller.
It seems you misunderstand the meaning of Population. There are no joins in MongoDB but sometimes we still want references to documents in other collections. This is where population comes in. Population is the process of automatically replacing the specified paths in the document with document(s) from other collection(s). So populate is not used to make document smaller.
Q3: Doctor, Patient, Practice
Schema could be as following:
var DoctorSchema = new Schema ({
name: String,
// ... other field
});
var PatientSchema = new Schema ({
name: String,
doctor: {type: Schema.ObjectId,
ref: 'Doctor'}
});
var PracticeSchema = new Schema ({
ff: String,
patientId: {type: Schema.ObjectId,
ref: 'Patient'},
doctorId: {type: Schema.ObjectId,
ref: 'Doctor'}
});
As for schema, it is hard to determine which schema is better or not, (with populate or without it). The first thing we should consider is to meet our query requirement, to make the query easy. The design of mongoDB to make the query more efficiently. So our schema should meet it.

Create/manage multidimensional array using jQuery [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I am building a chat application using socket.io.
I need to create an array to manage the users connected to each chat room.
To start with I need to store the chat room name, and then in that chat room each user and their status.
chat1
nickname: user1
status: admin
nickname: user2
status: none
nickname: user3
status: none
I need it to sort the nicknames in alphabetical order when it is created or when a user is added or deleted. Is this possible?
What you've described isn't a multidimensional array, it's an array of Objects or Maps. Assuming Objects:
chat1 = [
{ nickname: 'ethelred',
status: 'admin'},
{ nickname: 'alfred',
status: 'none' },
{ nickname: 'canute',
status: 'none' }
]
// This is all that's needed for a very simple sort:
chat1.sort((a,b) => a.nickname > b.nickname)
This will sort and give you [{nickname: 'alfred', status: 'none' }, {nickname: 'canute', status: 'none' }, { nickname: 'ethelred', status: 'admin'}]
// You can continue to transform the data,
// for example, just pull the user nicknames:
chat1.sort((a,b) => a.nickname - b.nickname)
.map(user => user.nickname)
That will sort and then map across the resulting sorted array to give you a list of users in alphabetical order - ['alfred','canute','ethelred'].
Note, this is naïve, you will need better logic in the sort function (what happens with capital letters, numbers, numbers mixed in with letters, &c?). But that function is completely isolated. You just write a separate (dumb) function that knows nothing about your chatroom object, and pass that to sort() with a.nickname and b.nickname as the arguments - chat1.sort(myFunkySortFunction(a.nickname, b.nickname)) (or you inline the logic and don't abstract it, whatever's simplest).
You'll start getting issues if you have a lot of users, as you'll need to run this on every join/leave event. At that point you'll need something a lot more robust.
Edit1:
So when a new person joins, they either get a. .push()-ed onto the original array, or b. you create a new array with the new person's object. When a person leaves, they either a. get removed from the original array, or b. a new array is created that doesn't include them.
When either of those events happen, you could run the sort function. You need to look at the Array.prototype.sort() method. That should literally be the only thing you need.
Note, what I'm suggesting is not very efficient, it will just do the job, and is very simple.
Re the function passed to sort, a.nickname > b.nickname is not going to work very well. A-Z will come before a-z. 'Xerxes' will come before 'albert'. You could do:
chat1.sort(function(a,b) {
return a.nickname.toLowerCase() > b.nickname.toLowerCase();
})
So that would sort that out. But you've still an issue with more complex names: it's worth looking at something robust like described here: Javascript : natural sort of alphanumerical strings
Basically, what you're doing isn't hard: you just need to make sure that in that callback function, you specify that you're grabbing the nickname property, otherwise it'll try to sort based on the whole object, and return weird incorrect results.
[very late] Edit2
I just realised that you asked how to add and remove. Staying on the same (functional) theme as the rest of the above: to add you can use Array.prototype.concat() to create a new array that includes the extra user. To remove, Array.prototype.filter() will return a new array with a specific user excised.
So add:
current = [
{ nickname: 'ethelred',
status: 'admin'},
{ nickname: 'alfred',
status: 'none' },
{ nickname: 'canute',
status: 'none' }
]
current.concat({ nickname: 'offa', status: 'none' })
// [{ nickname: 'ethelred', status: 'admin'}, { nickname: 'alfred', status: 'none'}, { nickname: 'canute', status: 'none'}, { nickname: 'offa', status: 'none'}]
To remove:
current = [
{ nickname: 'ethelred',
status: 'admin'},
{ nickname: 'alfred',
status: 'none' },
{ nickname: 'canute',
status: 'none' }
]
current.filter({nickname} => nickname !== 'canute')
// [{ nickname: 'ethelred', status: 'admin'}, { nickname: 'alfred', status: 'none'}]

Mongoose: Incrementing my documents version number doesn't work, and I'm getting a Version Error when I try to save

When I try to save my document, I'm getting a VersionError: No matching document found error, similar to this SO question.
After reading this blog post, it seems that the problem is with the versioning of my document. That I'm messing with an array and so I need to update the version.
However, calling document.save() doesn't work for me. When I log out the document before and after the call to save(), document._v is the same thing.
I also tried doing document._v = document._v++ which also didn't work.
Code
exports.update = function(req, res) {
if (req.body._id) { delete req.body._id; }
User.findById(req.params.id, function(err, user) {
if (err) return handleError(res, err);
if (!user) return res.send(404);
var updated = _.extend(user, req.body); // doesn't increment the version number. causes problems with saving. see http://aaronheckmann.blogspot.com/2012/06/mongoose-v3-part-1-versioning.html
console.log('pre increment: ', updated);
updated.increment();
// updated._v = updated._v++;
console.log('post increment: ', updated);
updated.save(function(err) {
if (err) return handleError(res, err);
return res.json(200, user);
});
});
};
Output
pre increment: { _id: 5550baae1b571aafa52f070c,
provider: 'local',
name: 'Adam',
email: 'azerner3#gmail.com',
hashedPassword: '/vahOqXwCwKQKtcV3KBQeFge/YB0xtqOj+YDyck7gzyALA/IP7u7BfqQhlVHBQT26//XfBTkaOCK2bQXg65OzA==',
salt: 'MvzXW7D4xuyGQBJNeFRoUg==',
__v: 32,
drafts: [],
starredSkims: [],
skimsCreated: [ 5550cfdab8dcacd1a7892aa4 ],
role: 'user' }
post increment: { _id: 5550baae1b571aafa52f070c,
provider: 'local',
name: 'Adam',
email: 'azerner3#gmail.com',
hashedPassword: '/vahOqXwCwKQKtcV3KBQeFge/YB0xtqOj+YDyck7gzyALA/IP7u7BfqQhlVHBQT26//XfBTkaOCK2bQXg65OzA==',
salt: 'MvzXW7D4xuyGQBJNeFRoUg==',
__v: 32,
drafts: [],
starredSkims: [],
skimsCreated: [ 5550cfdab8dcacd1a7892aa4 ],
role: 'user' }
The issue here has to do with using __v and trying to update it manually. .increment does not actually perform an increment immediately, but it does set an internal flag for the model to handle incrementing. I can't find any documentation on .increment, so I assume it is probably for use internally. The problem stems from trying to combine .extend with an object that already has __v (there are two underscores by the way, not that document.__v++ affects the model internally anyway) in addition to using .increment.
When you use _.extend it copies the __v property directly onto the object which seems to cause problems because Mongoose cannot find the old version internally. I didn't dig deep enough to find why this is specifically, but you can get around it by also adding delete req.body.__v.
Rather than finding and saving as two steps, you can also use .findByIdAndUpdate. Note that this does not use __v or increment it internally. As the other answer and linked bug indicate, if you want to increment the version during an update you have to do so manually.
Versioning was implemented to mitigate the doc.save() by design (not Model.update etc). But if you want you can try the following instead:
{$set: {dummy: [2]}, $inc: { __v: 1 }}
However this was a confirmed-bug according to the link
Please validate your mongoose version from the milestone of the above issue.
Thanks :)

Categories