How to change, customize, Mongoose default _id property? - node.js

I have the following schema:
const { ObjectId } = Schema.Types
const Account = new Schema({
name: { type: String, required: true },
accountId: { type: String, required: true },
piracicaba: [{ type: ObjectId, ref: 'Piracicaba'}]
})
I know that by default MongoDB creates an _id property, but I would like to make accountId my default ID instead. Also, I would like to change that default generated string to a custom one.
How could I do that?
I have tried to change the accountId type to ObjectId:
const { ObjectId } = Schema.Types
const Account = new Schema({
name: { type: String, required: true },
accountId: { type: ObjectId },
piracicaba: [{ type: ObjectId, ref: 'Piracicaba'}]
})
But then when I try to store my customized ID mongoose throws BSONTypeError: Argument passed in must be a string of 12 bytes or a string of 24 hex characters or an integer.
My customized ID is from Oracle Cloud Account and it looks like this: ocid1.test.oc1..<unique_ID>EXAMPLE-compartmentId-Value

If you include an _id field in your schema definition, when you insert a document you must supply it with your own manually generated _id. If you don't, the document will not get inserted.
Alternatively, if you do not include an _id field in your schema definition, Mongoose will create this for you automatically, when the document is inserted, and it will be of type ObjectId (which is the default way that MongoDB sets the _id field on documents).

Related

Dynamically create a collection field based on the user response with mongoose in mongo dB

I've a database collection where two types of users are there.
1.Customer: They will have all the basic functionalities.
2.Vendor: They will also have the basic functionalities available in addition they can create, delete, update and get/view the vehicles.
suppose a vendor created a vehicle so a vehicle id will get added to the vendor's collection likewise:
{
. /*other fields*/
.
.
listings: [
"uniqueId",
"uniqueId2"
]
}
I did some searching and found out that to add vehicle Id's to listings, the field needs to be created first in mongoose otherwise my data will not get inserted in mongodb through mongoose.
This rises a problem where all the users have listings field in them.
So, here's my user model I have created:
const userSchema = new mongoose.Schema({
user_type: {
type: String,
required: [true, "user type is required!"],
enum: ["customer", "vendor", "Customer", "Vendor"],
default: "customer"
},
listings: {
type: Array,
},//TODO: only create the listings array if the user type is vendor
});
So, my question is can I create this listing field only if the user_type is vendor?
As defined, in the mongoose documentation, Arrays have a default value of [].
So you'll need to override it. Try this:
const userSchema = new mongoose.Schema({
user_type: {
type: String,
required: [true, "user type is required!"],
enum: ["customer", "vendor", "Customer", "Vendor"],
default: "customer"
},
listings: {
type: [String], // can also be ObjectId
default: undefined
},
});

Accessing a Value in ENUM in a mongoose Schema

I'd like to access a specific value from an array enum in mongoose. I am fully aware that i can get the whole enum by DocumentModel.schema.path('user_role').enumValues but in the context below, i'd like to access the value Buyer under user_role.
The Schema looks like :
const userSchema = new mongoose.Schema({
user_role: {
type: String,
default: "Supplier",
enum: ["Buyer", "Supplier"],
},
user_fullName: {
type: String,
required: true
},
)}

object as property mongoose mongodb

I need a property in a mongoose model that is as following:
customRanks should have different keys and different values for each key
const config = new Schema({
id: { type: String, required: true, unique: true },
//...other property
customRanks: Object,
});
You can defined custome rank schema and use this as a object if you want to save data in specific format for customRanks fields
const customRanksSchema = new Schema({
key1: { type: Number, default: 0 },
key2: { type: Number, default: 0 },
key3: { type: String, default: '' }
})
If you want static schema and have specific fields for your custome rank object
// if you want to save customeRanks as array of object
customRanks: [{ type: customRanksSchema }],
// if you want to save custom rank as a object
customRanks: customRanksSchema
If you are looking for validation without key specifically. Then you may need to validate data before insert/create/update using javascript.

Is property `ref` necessary when schema field type is `ObjectId` in Mongoose?

I have a sample mongoose schema like below:
new Schema(
{
title: {
type: String,
},
digest: {
type: String,
},
owner: {
type: ObjectId,
ref: 'User'
}
}
)
I wonder to know that is property ref necessary when the field type is ObjectId like owner field.
No, not necessary, but if you have it, you'll be able to easily load the referenced entities. http://mongoosejs.com/docs/populate.html
Kitten.findOne().populate('owner').exec(function (err, kitten) {
console.log(kitten.owner.name) // Max
})
Without ref, it'll just be an ordinary field that contains ObjectId.

Using UUIDs in mongoose for ObjectID references

I'm building a CRUD-style REST service with Node.js, Express and MongoDB using mongoose. This service is going to allow users of an already existing android application to upload/sync the contents of their individual databases online.
The data model for the already-existing application uses UUIDs (generated in Java) which clashes with the shorter, monotonic MongoDB style _id fields. Because the data model already exists and is populated with data from many users, I cannot convert the source data over to monotonic MongoDB-style _ids. This has left me with 2 options that I can think of: either 1) Make Mongo/Mongoose (or some other ODM) play nicely with full UUIDs instead of the monotonic _ids or 2) add a uuid field to the mongoose model in addition to the _id field and fight the pitfalls of this approach. I'm attempting to choose option #1 and running into issues with ObjectID references.
I originally stumbled upon mongoose-uuid, but unfortunately this isn't working for my use-case properly because it was overwriting my explicitly-set _id value when creating new Mongoose objects. Diving into the plugin code, it assumes that an object is new (by calling checking Mongoose's .isNew value) and thus overwrites the _id with a new uuid. Since I need to retain the original uuid when creating new documents in Mongo, this plugin isn't working for me.
Next, I found a post by Aaron Heckmann, creator of mongoose, on a similar topic. This has been helpful, however I am now encountering the problem where I cannot have my mongoose schemas reference each other by ObjectID, since they technically they are now referencing each other using String `_ids.
Schema example:
var mongoose = require('mongoose');
var uuid = require('node-uuid');
var Schema = mongoose.Schema;
var trackPassSchema = new Schema({
_id: { type: String, default: function genUUID() {
uuid.v1()
}},
//Omitting other fields in snippet for simplicity
vehicle: [
{type: Schema.Types.ObjectId, required: true, ref: 'Vehicle'}
]
});
module.exports = mongoose.model('TrackPass', trackPassSchema);
Referencing schema:
var mongoose = require('mongoose');
var uuid = require('node-uuid');
var Schema = mongoose.Schema;
var vehicleSchema = new Schema({
_id: { type: String, default: function genUUID() {
uuid.v1()
}},
//Omitting other fields in snippet for simplicity
description: {type: String},
year: {type: Number}
});
module.exports = mongoose.model('Vehicle', vehicleSchema);
When I attempt to call save() a trackPass that has been passed in from my application:
var trackPass = new TrackPass(req.body);
//Force the ID to match what was put into the request
trackPass._id = req.params.id;
trackPass.save(function (err) { ... }
I get the following error:
{ [CastError: Cast to ObjectId failed for value "b205ac4d-fd96-4b1e-892a-d4fab818ea2a" at path "vehicle"]
message: 'Cast to ObjectId failed for value "b205ac4d-fd96-4b1e-892a-d4fab818ea2a" at path "vehicle"',
name: 'CastError',
type: 'ObjectId',
value: ["b205ac4d-fd96-4b1e-892a-d4fab818ea2a"],
path: 'vehicle' }
I believe this error makes sense as I'm now using Strings which are longer than typical Mongo ObjectIDs. Without having the ObjectID reference, I don't believe I will be able to populate() referenced objects from other collections. I suppose I could simply not reference the other nested objects in my schema definitions, however I don't like this approach as I feel I will be losing a lot of the benefit of utilizing the ODM. Any other thoughts?
You can still use populate() with _id values of types besides ObjectID, but you do need to use the same type in the reference definition.
So your trackPassSchema would need to change to:
var trackPassSchema = new Schema({
_id: { type: String, default: function genUUID() {
return uuid.v1()
}},
vehicle: [
{type: String, required: true, ref: 'Vehicle'}
]
});
As Adam notes in the comments, you could simplify your default value to:
var trackPassSchema = new Schema({
_id: { type: String, default: uuid.v1 },
vehicle: [
{type: String, required: true, ref: 'Vehicle'}
]
});
Both JohnnyHK and Adam C answers are correct. But if you're using uuid in schema for an array of objects, it is good to use it like this
var trackPassSchema = new Schema({
_id: { type: String, default: () => uuid.v1 },
vehicle: [
{type: String, required: true, ref: 'Vehicle'}
]
});
Because, in one such scenario when i tried using like this _id: { type: String, default: () => uuid.v1 } multiple objects of the array had the same id.
It is not possible in this case as _id is unique field, but it can happen when you are using with fields that aren't unique.

Resources