Typescript export default always executing - javascript

As a beginner in node js I cannot wrap my head around following problem.
import { createSchema, Type, typedModel } from "ts-mongoose";
const CompanySchema = createSchema(
{
companyName: Type.string({ required: true, unique: true })
},
{
timestamps: true
}
);
const Company = typedModel("Company", CompanySchema);
export { CompanySchema, Company };
This all works just fine until one point. When attempting to import this file.
import {CompanySchema, Company} from "./Company";
It executes typeModel method and stores the schema as expected. However, any other import of this file Company.ts reruns this method typeModel again. Which then fails because I can register schema with the name only once. How could I prevent of reruning this and still keep access to this object?
What would be general approach to this in order to keep access to both CompanySchema and Company object(as they will be later used in another schema as a reference)?

I don't know what the createSchema and typedModel are( if they are functions created by you or part of mongoose, the versions of mongoose ive worked with didnt have these functions )
...but I think you should not "createSchema" but define it instead.
e.g
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// define schema
const messageSchema = Schema({
sender: { type: Schema.Types.ObjectId, ref: 'User' },
recipient: { type: Schema.Types.ObjectId, ref: 'User' },
createdAt: { type: Date, default: Date.now },
deletedAt: { type: Date, default: undefined },
readAt: { type: Date, default: undefined},
message: { type: String, maxlength: 5000 }
});
// create a model based on that schema
const Message = mongoose.model('Message', messageSchema);
// Export the message model ... not the schema
module.exports.Message = Message;

Related

Mongoose Populate, Do I have to keep schemas in the same file?

I am trying to populate by using Mongoose. This is what it looks like so far:
schema.ts
const UserSchema = new mongoose.Schema({
id: String,
name: String,
});
const UserModel = mongoose.model("User", UserSchema, "users");
const ShiftSchema = new mongoose.Schema({
userId: {
type: String,
required: true,
},
date: {
type: String,
required: true,
},
startTime: String,
endTime: String,
});
ShiftSchema.virtual("user", {
ref: "User",
localField: "userId",
foreignField: "id",
justOne: true,
});
const ShiftModel = mongoose.model("Shift", ShiftSchema, "shifts");
export default ShiftModel;
shift.ts
const shifts = await ShiftModel.find({}).populate("user");
So this code is working fine, it is working as expects and populating user data into shift data.
What I'm currently having trouble with is organizing this. I need to separate schemas into separate files however if I try to separate the userSchema and UserModel into a different file, populate doesn't work anymore. Any ideas on a workaround for this?
Also, by the way, I am using a custom ID and not the default ID supplied by MongoDB.
What I've tried:
import mongoose from "mongoose";
export const UserSchema = new mongoose.Schema({
id: String,
name: String,
});
export const UserModel = mongoose.model("User", UserSchema, "users");
When I try to run my script, I get an error saying that Schema hasn't been registered for model "User".

How to reach information already saved in other related models... MongoDB, NodeJS

I'm really new at this and I want to practice queries and tried to make a very different exercise but it didn't went as I expected.
I got three models:
const userSchema = new Schema({
info1: String,
info2: String,
},
const serviceSchema = new Schema(
{
name: String,
legalOwner: {
type: Schema.Types.ObjectId,
ref: 'User',
},
},
const orderSchema = new Schema(
{
client: { type: Schema.Types.ObjectId, ref: 'User' },
service: { type: Schema.Types.ObjectId, ref: 'Service' },
description: String
},
My users can behave like a legal owner or a client. I want to show the info that a user set as a LegalOwner, previously. And that is already saved in Mongo, How can I have access that data, is there a query for that? Do I need to set it in my model Order?
const orderSchema = new Schema(
{
client: { type: Schema.Types.ObjectId, ref: 'User' },
service: { type: Schema.Types.ObjectId, ref: 'Service' },
description: String,
legalOwner: { type: Schema.Types.ObjectId, ref: 'Service' },
},
I tried a lot of things on this query. But nothing works ...
await Order.findById(id).populate('service')
ObjectId are stored as _id within mongoDb as far as I am aware of.
Try this
const query = { _id: new ObjectID(id)};
await Order.findOne(query).populate('service')
Also import ObjectID from mongodb node_module as
import { ObjectID } from 'mongodb';

Is it possible to define fields at the schema level that are calculated from another field using mongoose?

Is it possible to define fields at the schema level that are based off of another field using mongoose schemas?
For example, say I have this very simple schema:
const mongoose = require('mongoose')
const { Schema } = mongoose
const UserSchema = new Schema({
username: {
type: String,
required: true,
unique: true
},
username_lower: {
type: String,
// calculated: this.username.toLowerCase()
},
email: {
type: String,
required: true,
unique: true
},
email_lower: { // for case-insensitive email indexing/lookup
type: String,
// calculated: this.email.toLowerCase()
},
password: {
type: String,
required: true
},
password_acceptable: {
type: Array,
// calculated: [
// this.password.toLowerCase(),
// this.password.toUpperCase()
// this.password.removeWhiteSpace(), // just an example
// ]
}
})
const User = mongoose.model('User', UserSchema)
module.exports = User
Is there something similar to the dummy "calculated" fields (that I've commented out) that would allow automatic field creation when the new document is saved? This would be very convenient and would reduce the clutter from having to manually define these fields on my back-end routes.
Thank you very much for your help!
you can do it by Pre middleware function, for more details
UserSchema.pre('save', function(){
this.username_lower = this.username.toLowerCase();
this.email_lower = this.email.toLowerCase();
// and so on ...
next();
});

How to nest schemas in mongoose?

I'm trying to nest schemas using mongoose, but i got stuck and i don't really know why. Here is what i got.
My parent schema
const Comment = require("./Comment");
const BookSchema = new Schema({
_id: Number,
comments: [{ comment: Comment }],
ratings: [{ rate: Number }],
calculatedRating: Number
});
module.exports = Book = mongoose.model("book", BookSchema);
and child schema
const CommentSchema = new Schema(
{
userName: String,
rating: Number,
body: String,
submit_date: {
type: Date,
default: Date.now
}
},
{ _id: false }
);
module.exports = Comment = mongoose.model("comment", CommentSchema);
And with this setup im getting an error :
"TypeError: Invalid schema configuration: Model is not a valid type
at path comment."
I'm considering that i did something wrong with those exports but I'm not sure.
Your ./Comment should be:
const CommentSchema = new Schema(
{
userName: String,
rating: Number,
body: String,
submit_date: {
type: Date,
default: Date.now
}
},
{ _id: false }
);
module.exports = CommentSchema;
If you define as a new model as you did then it will create it's own collection and will be a new model instead of a sub document schema.

The same default value gets used every time by `new mongoose.Schema`

I have problem using uuid with new mongoose.Schema. I use it to generate unique key for a device and save it to the MongoDb using Node.js. the problem is that it uses the same UUID every time.
This is the model:
const mongoose = require('mongoose');
const uuid = require('uuid/v4');
const DeviceSchema = new mongoose.Schema({
deviceNumberHash: {
type: String,
required: true
},
receivingKey: {
type: String,
default: uuid()
}...
});
And this is what is saved in MongoDb:
Any idea what's wrong?
You're calling uuid and passing its return value in as the default to use.
Instead, pass in the function (by not putting () after it):
const DeviceSchema = new mongoose.Schema({
deviceNumberHash: {
type: String,
required: true
},
receivingKey: {
type: String,
default: uuid // <========== No ()
}...
});
The default can be a function per the docs (an example there uses default: Date.now to provide a default for a date field, for instance).

Categories