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

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;

Related

Use GraphQL Query to get results form MongoDB after aggregation with mongoose

so i have following problem.
I have a mongoDB collection and a corresponding mongoose model which looks like this.
export const ListItemSchema = new Schema<ListItemSchema>({
title: { type: String, required: true },
parentId: { type: Schema.Types.ObjectId, required: false },
});
export const TestSchema = new Schema<Test>(
{
title: { type: String, required: true },
list: { type: [ListItemSchema], required: false },
}
);
As you can see, my TestSchema holds an Array of ListItems inside -> TestSchema is also my Collection in MongoDB.
Now i want to query only my ListItems from a Test with a specific ID.
Well that was not that big of a problem at least from the MongoDB side.
I use MongoDB Aggregation Framework for this and call my aggregation inside a custom Resolver.
Here is the code to get an array of only my listItems from a specific TestModel
const test = TestModel.aggregate([
{$match: {_id: id}},
{$unwind: "$list"},
{
$match: {
"list.parentId": {$eq: null},
},
},
{$replaceRoot: {newRoot: "$list"}},
]);
This is the result
[ { _id: randomId,
title: 't',
parentId: null },
{ _id: randomId,
title: 'x'
parentId: null
} ]
The Query to trigger the resolver looks like this and is placed inside my Test Type Composer.
query getList {
test(testId:"2f334575196fe042ea83afbf", parentId: null) {
title
}
}
So far so good... BUT! Ofc my query will fail or will result in a not so good result^^ because GraphQL expects data based on the Test-Model but receives a completely random array.
So after a lot of typing here is the question:
How do i have to change my query to receive the list array?
Do i have to adjust the query or is it something with mongoose?
i really stuck at this point so any help would be awesome!
Thanks in advance :)
I'm not sure if I understood your issue correctly.
In your graphql, try to leave out exclamation mark(!) from the Query type.
something like :
type Query {
test: TestModel
}
instead of
type Query {
test: TestModel!
}
then you'll get the error message in console but still be able to receive any form of data.

How to remove _id from collection in mongodb using mongoose

Tried to remove _id from collection but not working. I do not know how to resolve this issue. Need help anyone.
model.js:
const schemmaodel = new mongoose.Schema({
"name": { type: string}
}, { _id: false, versionKey: false });
data.controller.js:
var newModel = require(path.resolve('./models/model.js'))(collectionName);
newModel.create({}, function(err, doc) {
});
_id is like a primary key for the collection. If _id is not specified in the Schema then Mongoose will by default _id of type ObjectId.
As per the mongoose documentation you can disable _id on subdocuments only. So in your case, schemmaodel is considered as parent schema and since you have set { _id: false } option on parent schema while saving it will throw an error related to missing _id

How to define mongoose schema for nested documents

I need to define the mongoose schema for for nested documents which is given below.
Documents:
"Options":[{"Value":["28","30","32","34","36","38","40","42","44","46"],"_id":{"$oid":"5de8427af55716115dd43c8f"},"Name":"Size"},{"Value":["White"],"_id":{"$oid":"5de8427af55716115dd43c8e"},"Name":"Colour"}]
I was declaring like below but its not working.
const Product = new Schema(
{
Options: [{ value: { _id: ObjectId, Name: String } }]
},
{
timestamps: {
createdAt: "createdAt",
updatedAt: "updatedAt"
},
collection: "products"
}
);
Here I need the schema where if i will directly add/update the same document then it will be added.
You need to modify your schema like this :
{
Options: [ new Schema ({ value: [...], _id: Schema.Types.ObjectId, Name: String })]
}
This is the way to create an array of subdocuments with Mongoose. If you don't use the "new Schema" key words, you are actually creating a field with type "Mixed", which needs a different way to handle updates.
You can also omit the _id, it should be added automatically.
You can find more information on subdocument on this page :
https://mongoosejs.com/docs/subdocs.html
...and on mixed type fields : https://mongoosejs.com/docs/schematypes.html#mixed
...which will explain shortly the problem.
{
Options: [ new Schema ({ _id: mongoose.Types.ObjectId(),value: [String], Name: String } })]
}

mongoose different ways to reference subdocuments?

This syntax is straight from the mongoose documentation on subtypes. However, I've also seen this alternate reference to subdocs. What is the difference?
https://mongoosejs.com/docs/subdocs.html
var childSchema = new Schema({ name: 'string' });
var parentSchema = new Schema({
// Array of subdocuments
children: [childSchema],
// Single nested subdocuments. Caveat: single nested subdocs only work
// in mongoose >= 4.2.0
child: childSchema
});
An alternate type of reference to subdocs
var childSchema = new Schema({ name: 'string' });
mongoose.model('children', childSchema);
var parentSchema = new Schema({
children: {
type: Schema.Types.ObjectId,
ref: 'children'
},
});
The above two syntax are totally different, In one the actual sub-document(children ) is stored in the parent document, but in the other one, a new document is stored in the children collection and only its reference is stored in the parent document.
Case 1:
var childSchema = new Schema({ name: 'string' });
var parentSchema = new Schema({
// Array of subdocuments
children: [childSchema],
// Single nested subdocuments. Caveat: single nested subdocs only work
// in mongoose >= 4.2.0
child: childSchema
});
In this given syntax, parent document will have the child document stored in the parent document as well.
A sample document in the parent sollection will look like this:
{
_id : "parent_random_generated_id"
children :[{ _id : "childid1" , name : "Captain America"},
{ _id : "childid2" , name : "Iron Man"},...],
child : {_id : "childid3" , name : "Thor Odinson"},
...
}
Case 2:
var childSchema = new Schema({ name: 'string' });
mongoose.model('children', childSchema);
var parentSchema = new Schema({
children: {
type: Schema.Types.ObjectId,
ref: 'children'
},
});
In this syntax, child documents will be stored separately, and they reference id (_id) will be stored in the parent document.
Sample documents in this case will look something like this:
// Children documents
{ _id : "childid1" , name : "Captain America"}
{ _id : "childid2" , name : "Iron Man"}
{ _id : "childid3" , name : "Thor Odinson"}
//parent document
{
_id : "parent_random_generated_id"
children :["childid1","childid2",...],
child : "childid3",
...
}
In the second case you can use Mongodb $lookup operator to populate the sub documents, whenever needed, using mongodb aggregation pipeline, or use .populate('children') or .populate('child') to pupulate the specific child document.
I hope this clarifies your doubt.
I have completed
Ravi Shankar Bharti Case 2 with some data writing example. Let's use a book-author scenario:
const authorSchema = new Schema({ name: 'string' });
const authorModel = mongoose.model('authors', authorSchema);
const bookSchema = new Schema({
title: String,
author: {
type: Schema.Types.ObjectId,
ref: 'author'
},
});
const bookModel = mongoose.model('books', bookSchema)
const authorData = { name: "John Doe" }
// Check if author does exists. Insert if not or find if yes
const options = {
upsert: true,
new: true,
setDefaultsOnInsert: true
};
const anAuthor = await authorModel.findOneAndUpdate(authorData, authorData, options)
// Insert a new book with reference to `anAuthor`
const aBook = new bookModel({ title: "MyBook" })
aBook.set({ author: anAuthor })
await aBook.save()
In this syntax, child documents will be stored separately, and they reference id (_id) will be stored in the parent document.
Sample documents in this case will look something like this:
// authors documents
{ _id : "authorId1" , name : "John Doe"}
{ _id : "authorId2" , name : "Iron Man"}
{ _id : "authorId3" , name : "Thor Odinson"}
//books document
{
_id : "parent_random_generated_id"
title: "MyBook",
author : "authorId1",
...
}
And for reading, you can use populate:
let result = await bookModel.find()
result = await authorModel.populate(result, { path: 'author' })
Difference is pretty simple. The former one where you are just defining schema for child won't create a separate collection for the children in the database instead you will embed the whole child document in the parent.
And in the later one you are defining a model for the child schema by calling mongoose.model which creates a separate collection of children in the database and you can then reference child documents in the parent document without embedding the whole child document in the parent by just adding the child _id.

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;