How to exclude one particular field from a collection in Mongoose? - javascript

I have a NodeJS application with Mongoose ODM(Mongoose 3.3.1). I want to retrieve all fields except 1 from my collection.For Example: I have a collection Product Which have 6 fields,I want to select all except a field "Image" . I used "exclude" method, but got error..
This was my code.
var Query = models.Product.find();
Query.exclude('title Image');
if (req.params.id) {
Query.where('_id', req.params.id);
}
Query.exec(function (err, product) {
if (!err) {
return res.send({ 'statusCode': 200, 'statusText': 'OK', 'data': product });
} else {
return res.send(500);
}
});
But this returns error
Express
500 TypeError: Object #<Query> has no method 'exclude'.........
Also I tried, var Query = models.Product.find().exclude('title','Image'); and var Query = models.Product.find({}).exclude('title','Image'); But getting the same error. How to exclude one/(two) particular fields from a collection in Mongoose.

Use query.select for field selection in the current (3.x) Mongoose builds.
Prefix a field name you want to exclude with a -; so in your case:
Query.select('-Image');
Quick aside: in JavaScript, variables starting with a capital letter should be reserved for constructor functions. So consider renaming Query as query in your code.

I don't know where you read about that .exclude function, because I can't find it in any documentation.
But you can exclude fields by using the second parameter of the find method.
Here is an example from the official documentation:
db.inventory.find( { type: 'food' }, { type:0 } )
This operation returns all documents where the value of the type field is food, but does not include the type field in the output.

Model.findOne({ _id: Your Id}, { password: 0, name: 0 }, function(err, user){
// put your code
});
this code worked in my project. Thanks!! have a nice day.

You could do this
const products = await Product.find().select(['-image'])

I am use this with async await
async (req, res) => {
try {
await User.findById(req.user,'name email',(err, user) => {
if(err || !user){
return res.status(404)
} else {
return res.status(200).json({
user,
});
}
});
} catch (error) {
console.log(error);
}

In the updated version of Mongoose you can use it in this way as below to get selected fields.
user.findById({_id: req.body.id}, 'username phno address').then(response => {
res.status(200).json({
result: true,
details: response
});
}).catch(err => {
res.status(500).json({ result: false });
});

I'm working on a feature. I store a userId array name "collectedUser" than who is collected the project. And I just want to return a field "isCollected" instead of "collectedUsers". So select is not what I want. But I got this solution.
This is after I get projects from database, I add "isCollected".
for (const item of projects) {
item.set("isCollected", item.collectedUsers.includes(userId), {
strict: false,
})
}
And this is in Decorator #Schema
#Schema({
timestamps: true,
toObject: {
virtuals: true,
versionKey: false,
transform: (doc, ret, options): Partial<Project> => {
return {
...ret,
projectManagers: undefined,
projectMembers: undefined,
collectedUsers: undefined
}
}
}
})
Finally in my controller
projects = projects.map(i => i.toObject())
It's a strange tricks that set undefined, but it really work.
Btw I'm using nestjs.

You can do it like this
const products = await Product.find().select({
"image": 0
});

For anyone looking for a way to always omit a field - more like a global option rather than doing so in the query e.g. a password field, using a getter that returns undefined also works
{
password: {
type: String,
required: true,
get: () => undefined,
},
}
NB: Getters must be enabled with option { toObject: { getters:true } }

you can exclude the field from the schema definition
by adding the attribute
excludedField : {
...
select: false,
...
}
whenever you want to add it to your result,
add this to your find()
find().select('+excludedFiled')

Related

Mongoose Select Method Not Working As Expected

Trying to simply include a field that has select set to false within the schema. Overriding it with select method is not working for some reason. Exclusion of other fields work but inclusion doesn't. In the following example I'm trying to include the "active_account" field. What could be causing this behavior?
Schema
const Schema = new mongoose.Schema({
active_account: {
type: Boolean,
default: true,
select: false
}
})
Function
exports.deactivate_user = async ( req , res , next ) => {
const user = await User.findByIdAndUpdate( req.params.id , { active_account: false } ).select( '+active_account' );
res.status( 200 ).json({
status: 'Success',
data: user
});
};
According to docs;
A.findByIdAndUpdate(id, update, options) // returns Query
So,
const user = await User.findByIdAndUpdate(
req.params.id, //id
{ active_account: false }, //update
{ select: 'active_account', new: true } //options
);
set new = true to get the updated version of data.

Mongoose: only one unique boolean key should be true

I have two schema collections:
Campaigns:{
_id: "someGeneratedID"
//...a lot of key value pairs.
//then i have teams which is an, array of teams from the Team schema.
teams:teams: [{ type: mongoose.Schema.Types.ObjectId, ref: "Team" }],
}
Teams:{
campaignId: { type: mongoose.Schema.Types.ObjectId, ref: "Campaign" },
isDefault: { type: Boolean, default: false },
}
Now I would like that when I add teams to the collection, it should throw an error if there are more than 2 isDefault:true per campaignId.
so the following shouldn't be allowed:
teams:[
{
campaignId:1,
teamName:"John Doe"
isDefault:true,
}
{
campaignId:1,
teamName:"Jane Doe"
isDefault:true
}
]
I found this answer on SO:
teamSchema.index(
{ isDefault: 1 },
{
unique: true,
partialFilterExpression: { isDefault: true },
}
But couldn't manage to also check for the campaignId.
Thanks in advance.
ps: can you also provide an explanation for what's happening in the index method?
I think that the simplest way to approach this is via Mongoose's middleware pre('save'). This method will give you a way to check all the campaigns listed in the collection in order to check if any of the items is already set as default.
teamSchema.pre("save", async function (next) {
try {
if ((this.isNew || this.isModified("isDefault") && this.isDefault) {
const previousDefault = await mongoose.models["Team"].findOne({ isDefault: true, campaignId: this.campaignId });
if (previousDefault) {
throw new Error('There is already default team for this campaign');
}
}
next();
} catch (error) {
throw error;
}
});
This way, if any team, either new or already existing, is set as default for a given campaign, before its record is saved, the whole collection will be searched for any entry with isDefault already set to true. If at least one item is found, we will throw an error. If not, next() guarantees the save() method will go on.

Mongodb using dynamic fields with $not

I programming in react, mongodb, nodejs and expressjs. I have a problem that I cannot solve. I would like to use dynamic fields from $not on the server. For example, the server gets the column name from the front and it is supposed to return the number of documents where the text is different from an empty string, i.e. ''. I've tried to do something like this(code below), but it doesn't help.
const query = {};
query[type] = { $not: '' };
User.countDocuments(query, (err, data) => {
if (err) return res.json({ success: false, error: err });
return res.json({ success: true, data: data });
});
You are close, you probably were looking for $ne instead of $not. So changing it to
const query = {};
query[type] = { $ne: '' };
should fix the issue. This would find all documents where the dynamic type field does not equal ''. If you want to do the inverse, i.e. find all documents where the dynamic field equals an empty string, change it to:
query[type] = { $eq: '' };

How can I add to this schema array with mongoose?

Here's the user schema and the part I want to update is ToDo under User.js (further down). I am attempting to add new data to an array within the db.
data.js
app.post("/data", loggedIn, async (req, res) => {
console.log(req.body.content);
let content = { content: req.body.content };
User.update({ _id: req.user._id }, { $set: req.body }, function (err, user) {
if (err) console.log(err);
if (!content) {
req.flash("error", "One or more fields are empty");
return res.redirect("/");
}
user.ToDo.push(content);
res.redirect("/main");
});
});
User.js
new mongoose.Schema({
email: String,
passwordHash: String,
ToDo: {
type: [],
},
date: {
type: Date,
default: Date.now,
},
})
Originally I was trying the .push() attribute, but I get the error:
user.ToDo.push(content);
^
TypeError: Cannot read property 'push' of undefined
First of all, your problem is the callback is not the user. When you use update the callback is something like this:
{ n: 1, nModified: 1, ok: 1 }
This is why the error is thrown.
Also I recommend specify the array value, something like this:
ToDo: {
type: [String],
}
The second recommendation is to do all you can into mongo query. If you can use a query to push the object, do this instead of store the object into memory, push using JS function and save again the object into DB.
Of course you can do that, but I think is worse.
Now, knowing this, if you only want to add a value into an array, try this query:
var update = await model.updateOne({
"email": "email"
},
{
"$push": {
"ToDo": "new value"
}
})
Check the example here
You are using $set to your object, so you are creating a new object with new values.
Check here how $set works.
If fields no exists, will be added, otherwise are updated. If you only want to add an element into an array from a specified field, you should $push into the field.
Following your code, maybe you wanted to do something similar to this:
model.findOne({ "email": "email" }, async function (err, user) {
//Here, user is the object user
user.ToDo.push("value")
user.save()
})
As I said before, that works, but is better do in a query.

Mongoose : Add an element to an array of Objects under an Object field

I'm trying to add an element to an array of Objects under an Object field
This in my mongoose "Utilisateur" schema:
So what i'm trying to do here is to add an element to the "lien_vers" array
this is the code that i wrote
Utilisateur.findOneAndUpdate({ _id: mongoose.Types.ObjectId(auteur._id) },
{
$push: {
'relations.lien_vers': {
metadonnees: { nom_societe: societePersonalId },
identite: auteur._id.toString(),
canons: [""]
}
}
}, { upsert: true }
, function (error, doc) {
if (err) {
console.log("Something wrong when updating data!", err);
}
console.log("updated", doc.relations);
});
i've got no errors but there is no changes ! it seems like the update is not working correctly
Any help plz
By default, findOneAndUpdate() returns the document as it was before update was applied. If you set new: true, findOneAndUpdate() will instead give you the object after update was applied.
Your code looks fine, the record is updated in your db, it just return the document before update in your callback. To get the updated document, you just need to add new: true to the options.
Eventually this solution worked for me
I insist on adding markModified() so that the save() method can detect changes
Utilisateur.findOne({ _id: mongoose.Types.ObjectId(auteur._id) }, function (err, sal) {
if (err) return handleError(err);
else {
sal.relations.lien_vers.push({
metadonnees: { nom_societe: societePersonalId },
identite: auteur._id.toString(),
canons: [""]
});
console.log("before saving", sal.relations.lien_vers)
sal.markModified('relations');
sal.save(function (err) {
if (err) {
console.log(err)
}
console.log("doc saved")
});
}
});
}

Categories

Resources