mongoose how to project protected fields on update - mongodb

I have following model in mongoose. projects field is protected.
var UserProjectSchema = new Schema({
user : ObjectId
, projects : {type : [ObjectId], select:false} //protected field
, projectCount : Number
});
I want that protected field after update so that I could return the new set of projects.
UserProjectSchema.statics.addProject = function(userId, projectId) {
UserProject.findOneAndUpdate({
user:userId
},
{
$addToSet: {"projects" : projectId}
, $inc : {"projectCount" : 1}
},
{
upsert : true
//project : '+projects' it won't work
},
function(err, doc){
//doc.projects is undefined
// UserProject.findOne({user:userId},'+projects', function(err, doc){
// doc.projects is now available but this extra query ???
//})
});
}
var UserProject = mongoose.model('user_projects', UserProjectSchema);
Mongoose returns the updated document after successful query but lacks to specify the fields to project.
Is there any way to specify what fields to project after updating in mongoose so that I could remove the extra query ?

Include a select parameter in your options param and list all the fields you would like to project.
{
upsert : true,
select:{"projects":1} // all the fields you would want to select
}

Related

MongoDB Atlas trigger does not set field

I have the following trigger function that is not function. I would like to know why it does not set the field createdAt:
const collection = context.services.get("comand-dev").db("test").collection("ownerDetails");
const docId = changeEvent.documentKey._id;
collection;
collection.updateOne(
{_id : docId} ,
{
$set :
{
createdAt: Date()
}
}
);
The trigger logs says OK but the field is not there
This worked for me. A small issue with the syntax. you have to add the quotes.
collection.updateOne(
{"_id" : docId} ,
{
"$set" :
{
"createdat": Date()
}
}
);
I was able to figure out so I would share my solution. In my case, I convert _id object id to date and insert it as a new field for newly inserted document. The trigger will be configurated as insert trigger operation. Enable event ordering.
exports = function (changeEvent) {
const docId = changeEvent.documentKey._id;
console.log(docId);
const collection =
context.services.get("Cluster0").db("Driver").collection("Trip");
collection.updateOne({_id: docId },
[{
"$addFields" : {
"CreationDate" : {
"$toDate" : "$_id"
}
}
}],{upsert: false}
);
};

How Mongoose generate an ObjectId on non-collection field? [duplicate]

If you have subdocument arrays, Mongoose automatically creates ids for each one. Example:
{
_id: "mainId"
subDocArray: [
{
_id: "unwantedId",
field: "value"
},
{
_id: "unwantedId",
field: "value"
}
]
}
Is there a way to tell Mongoose to not create ids for objects within an array?
It's simple, you can define this in the subschema :
var mongoose = require("mongoose");
var subSchema = mongoose.Schema({
// your subschema content
}, { _id : false });
var schema = mongoose.Schema({
// schema content
subSchemaCollection : [subSchema]
});
var model = mongoose.model('tablename', schema);
You can create sub-documents without schema and avoid _id. Just add _id: false to your subdocument declaration.
var schema = new mongoose.Schema({
field1: {
type: String
},
subdocArray: [{
_id: false,
field: { type: String }
}]
});
This will prevent the creation of an _id field in your subdoc.
Tested in Mongoose v5.9.10
Additionally, if you use an object literal syntax for specifying a sub-schema, you may also just add _id: false to supress it.
{
sub: {
property1: String,
property2: String,
_id: false
}
}
I'm using mongoose 4.6.3 and all I had to do was add _id: false in the schema, no need to make a subschema.
{
_id: ObjectId
subDocArray: [
{
_id: false,
field: "String"
}
]
}
You can use either of the one
var subSchema = mongoose.Schema({
//subschema fields
},{ _id : false });
or
var subSchema = mongoose.Schema({
//subschema content
_id : false
});
Check your mongoose version before using the second option
If you want to use a predefined schema (with _id) as subdocument (without _id), you can do as follow in theory :
const sourceSchema = mongoose.Schema({
key : value
})
const subSourceSchema = sourceSchema.clone().set('_id',false);
But that didn't work for me. So I added that :
delete subSourceSchema.paths._id;
Now I can include subSourceSchema in my parent document without _id.
I'm not sure this is the clean way to do it, but it work.
NestJS example for anyone looking for a solution with decorators
#Schema({_id: false})
export class MySubDocument {
#Prop()
id: string;
}
Below is some additional information from the Mongoose Schema Type definitions for id and _id:
/**
* Mongoose assigns each of your schemas an id virtual getter by default which returns the document's _id field
* cast to a string, or in the case of ObjectIds, its hexString.
*/
id?: boolean;
/**
* Mongoose assigns each of your schemas an _id field by default if one is not passed into the Schema
* constructor. The type assigned is an ObjectId to coincide with MongoDB's default behavior. If you
* don't want an _id added to your schema at all, you may disable it using this option.
*/
_id?: boolean;

Mongoose inserts extra _id in array of objects corresponding to related entity [duplicate]

If you have subdocument arrays, Mongoose automatically creates ids for each one. Example:
{
_id: "mainId"
subDocArray: [
{
_id: "unwantedId",
field: "value"
},
{
_id: "unwantedId",
field: "value"
}
]
}
Is there a way to tell Mongoose to not create ids for objects within an array?
It's simple, you can define this in the subschema :
var mongoose = require("mongoose");
var subSchema = mongoose.Schema({
// your subschema content
}, { _id : false });
var schema = mongoose.Schema({
// schema content
subSchemaCollection : [subSchema]
});
var model = mongoose.model('tablename', schema);
You can create sub-documents without schema and avoid _id. Just add _id: false to your subdocument declaration.
var schema = new mongoose.Schema({
field1: {
type: String
},
subdocArray: [{
_id: false,
field: { type: String }
}]
});
This will prevent the creation of an _id field in your subdoc.
Tested in Mongoose v5.9.10
Additionally, if you use an object literal syntax for specifying a sub-schema, you may also just add _id: false to supress it.
{
sub: {
property1: String,
property2: String,
_id: false
}
}
I'm using mongoose 4.6.3 and all I had to do was add _id: false in the schema, no need to make a subschema.
{
_id: ObjectId
subDocArray: [
{
_id: false,
field: "String"
}
]
}
You can use either of the one
var subSchema = mongoose.Schema({
//subschema fields
},{ _id : false });
or
var subSchema = mongoose.Schema({
//subschema content
_id : false
});
Check your mongoose version before using the second option
If you want to use a predefined schema (with _id) as subdocument (without _id), you can do as follow in theory :
const sourceSchema = mongoose.Schema({
key : value
})
const subSourceSchema = sourceSchema.clone().set('_id',false);
But that didn't work for me. So I added that :
delete subSourceSchema.paths._id;
Now I can include subSourceSchema in my parent document without _id.
I'm not sure this is the clean way to do it, but it work.
NestJS example for anyone looking for a solution with decorators
#Schema({_id: false})
export class MySubDocument {
#Prop()
id: string;
}
Below is some additional information from the Mongoose Schema Type definitions for id and _id:
/**
* Mongoose assigns each of your schemas an id virtual getter by default which returns the document's _id field
* cast to a string, or in the case of ObjectIds, its hexString.
*/
id?: boolean;
/**
* Mongoose assigns each of your schemas an _id field by default if one is not passed into the Schema
* constructor. The type assigned is an ObjectId to coincide with MongoDB's default behavior. If you
* don't want an _id added to your schema at all, you may disable it using this option.
*/
_id?: boolean;

How to dynamically $set a subdocument field in mongodb? [duplicate]

This question already has answers here:
Nodejs Mongo insert into subdocument - dynamic fieldname
(2 answers)
Closed 8 years ago.
I've run into a situation where I need to dynamically update the value of a field in a subdocument. The field may or may not already exist. If it doesn't exist, I'd like mongo to create it.
Here's an example document that would be found in my Teams collection, which is used to store members of any given team:
{
_id : ObjectId('JKS78678923SDFD678'),
name : "Bob Lawblaw",
status : "admin",
options : {
one : "One",
two : "Two"
}
}
And here's the query I'm using (I'm using mongojs as my mongo client) to try and update (or create) a value in the options subdocument:
var projectID = 'JKS78678923SDFD678';
var key = 'Three';
var value = 'Three';
Teams.findAndModify({
query: {
projectID:mongojs.ObjectId(projectID)
},
update: {
$set : { options[key] : value }
},
upsert: true,
multi: false,
new: true
},
function(error, result, lastErrorObject){
console.log(result);
});
But I can't get it to 'upsert' the value.
I also found this similar question, but that method didn't work either:
Nodejs Mongo insert into subdocument - dynamic fieldname
Thanks in advance for any help.
Figured this out.
Essentially, you need to construct a 'placeholder' object of the sub-document you're trying to update before running the query, like so:
var projectID = 'JKS78678923SDFD678';
var key = 'Three';
var value = 'Three';
var placeholder = {};
placeholder['options.' + key] = value;
Teams.findAndModify({
query: {
projectID:mongojs.ObjectId(projectID)
},
update: {
$set : placeholder
},
upsert: true,
multi: false,
new: true
},
function(error, result, lastErrorObject){
console.log(result);
});
This updates any fields that already exist, and creates the field/value pair if it didn't already exist.

Get all fields names in a mongodb collection?

I'm coding a mongoose schema so I need a list of possible field in my collection.
Please how can I display all fields names in a specific collection, thank you.
switch to the db you're using and type:
mr = db.runCommand({
"mapreduce" : "myCollectionName",
"map" : function() {
for (var key in this) { emit(key, null); }
},
"reduce" : function(key, stuff) { return null; },
"out": "myCollectionName" + "_keys"
})
once you get result, type:
db[mr.result].distinct("_id")
and you will get a list of fields names.