Getting id in mongoose post update One hook - node.js

This is my mongoose model:
import mongoose, { Schema, Document } from "mongoose";
export interface IUserModel extends Document {
username: string;
id: string;
}
const UserSchema: Schema = new Schema({
username: { type: String },
_id: { type: String }
});
UserSchema.post('updateOne', (doc) => {
console.log("doc._id",doc._id);
});
const UserModel = mongoose.model<IUserModel>("user", UserSchema);
export default UserModel;
I need to access the unique _id in the post hook after I have called updateOne method to call some logic with that id.
However doc._id prints undefined as does doc.id.
when I console.log this it prints to the console:
{ default: Model { user } }
But when I try to access this["default"] it again gives error.
I am calling update method like this :
await UserModel.updateOne({_id: id},userModel)
mongoose version : "^5.11.10"
#types/mongoose version : "^5.10.3"
Any help will be greatly appreciated.

Related

TypeGraphQL Field Resolver with mongoose relationship

I have trouble dealing with populating the field using TypeGraphQL.
Situation summary with an example:
TypeGraphQL
TypeDef
#ObjectType()
class User {
...
}
#ObjectType()
class Post {
...
#Field()
user: User
}
Resolver
import { Post, User } from '#/models' // mongoose schema
#Resolver(() => Post)
class PostResolver {
#Query(() =>. Post)
async getPost(id: string) {
return await Post.findById(id);
}
...
#FieldReoslver(() => User)
async user(#Root() post: Post) {
return await User.findById(post.user) // Error Occurs here.
}
}
Mongoose
PostSchema
const PostSchema = new Schema({
...
user: {
type: Schema.ObjectId,
ref: "User",
}
})
I want to populate user field when the data Post is requested, with the field User type.
So, I used #FieldResolverlike above, but I encountered the Type Error because post.user is a type of User, not ObjectId of mongoose.
The user field is a type of ObjectId first when the getPost resolver was executed, but I want to populate this field to User when the client gets the response.
How can I get through this?
Thanks in advance.

tsc doesn't recognize virtuals on mongoose scheme

I love mongoose virtual but I can't make it work in typescript.
I'm using mongoose's InferSchemaType to create the interface as described in "another approach:" in mongoose documentation
TSC doesn't recognize them as a field in the interface.
I tried in both suggested manners (see code below).
import {connect, InferSchemaType, Schema, model} from 'mongoose';
const url = 'mongodb://admin:admin#0.0.0.0:27017/';
export const DBS_Actor = new Schema(
{
firstName: String,
lastName: String,
},
{
virtuals: {
fullName: {
get() {
return this.firstName + ' ' + this.lastName;
},
},
},
}
);
DBS_Actor.virtual('tagname').get(function () {
return 'Secrete Agent 007';
});
export type IActor = InferSchemaType<typeof DBS_Actor>;
export const Actor = model<IActor>('User', DBS_Actor);
run().catch(err => console.log(err));
async function run() {
await connect(url);
const actor = new Actor({
firstName: 'jojo',
lastName: 'kiki',
});
await actor.save();
console.log(actor.toJSON()); // {firstName: 'jojo', lastName: 'kiki', _id: new ObjectId("62e52b18d41b2bd4d2bd08d8"), __v: 0 }
console.log(actor.firstName); // jojo
// console.log(actor.fullname); //TSC error TS2339: Property 'fullname' does not exist on typ
// console.log(actor.tagname); //TSC error TS2339: Property 'tagname' does not exist on type...
}
You can extend your type if you want to use additional fields on your type:
export type IActor = InferSchemaType<typeof DBS_Actor> & {
firstName: String
};

How to insert data in mongodb using mongoose in typescript?

I had implemented a typescript code for a crud API but currently, I'm facing an issue while inserting data using API using the mongoose package. AS my database is MongoDB so I have used this package.
import Transaction from 'mongoose-transactions-typescript';
I am working on typescript project so that's why I have used this package
public async createAffiliateUser(res_data: any){
console.log("Function");
const transaction = new Transaction();
console.log("Function123");
const AffiliateUserModelName = 'affiliateusers'; // COLLECTION name
console.log(res_data);
await transaction.insert(AffiliateUserModelName, {
name: res_data.name,
userName: res_data.userName,
groupId: res_data.groupId,
commissionCount: res_data.commissionCount,
commissionAmount: res_data.commissionAmount,
is_active: res_data.is_active
});
return await transaction.run();
}
In the above code highlighted line throwing an error like this
TypeError:mongoose_transactions_typescript_1.default is not a constructor
In the above function when I tried to use default create method of mongoose it inserting only single column data even though passing full data as below
{
"name": "Test",
"userName":"test123",
"groupId": "1",
"commissionCount": 1,
"commissionAmount": 2,
"is_active": true
}
So if anyone knows how to insert data in MongoDB using typescript or a solution for the above problem then pls help me to resolve this?
Thank you
I don't know why you are this code structure in order to use mongoose.
The steps that I follow in order to use correctly mongodb documents with mongoose are these:
create a mongoose model schema like this:
// I usually like create this file in a database folder
import mongoose, { Document, Model } from "mongoose";
const Schema = mongoose.Schema;
// creating the actual mongoose schema
const UserSchema = new Schema(
{
firstName: {
type: String,
},
lastName: {
type: String,
},
username: {
type: String,
},
lang: {
type: String,
default: "it",
},
},
{ timestamps: true }
);
// exporting the type in order to have all the correct linting
export interface IUser extends Document {
id: string;
firstName: string;
lastName?: string;
username?: string;
createdAt: Date | number;
updatedAt: Date | number;
}
// registering in mongoose models the schema with the relative interface
const User =
(mongoose.models.User as Model<IUser>) ||
mongoose.model<IUser>("User", UserSchema);
export default User;
at this point let's suppose that you have a tree similar to this:
root_folder
|-- database
| |-- User.ts
|
|-- controllers
|-- addUser.ts
creating the document in the collection:
import { User } from "../../database/User.ts"
async function addUser(){
const newUser = await new User({firstName: "foo", lastName: "bar", username:"testUser"}).save()
}
and now you should have your fresh document in the users collection

Mongoose - Can't push a subdocument into an array in parent Document

I am trying to push a subdocument(ApplicationSchema) into my Job schema. But it doesn't seem to work.
Following is my Job Schema :
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
var ApplicationSchema = require('./Application');
const Job = new Schema({
skills : {
type : Array
},
active : {
type : Boolean,
default : false
},
applications: [ApplicationSchema],
userId : {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
},{timestamps : true});
export default mongoose.model("Job", Job)
This is subdocument(ApplicationSchema). I have 5 more subdocuments in this schema.
I am pushing an object with a key-value pair of talentId and its value. But it doesn't work.
I get a new object in the array but the object I'm trying to push is not pushed.
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
var notesSchema = require('./notesSchema');
var documentSchema = require('./documentSchema');
var assessmentSchema = require('./assessmentSchema');
var interviewScheduleSchema = require('./interviewScheduleSchema');
var referenceSchema = require('./referenceSchema')
const ApplicationSchema = new Schema({
talentId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Talent'
},
applicationType: {
type: Number
}
notes: [notesSchema],
documents: [documentSchema],
assessment: [assessmentSchema],
interviewSchedule: [interviewScheduleSchema],
references: [referenceSchema]
},{
timestamps: true
});
export default ApplicationSchema;
Following is my code in the API endpoint
.post((req, res, next) => {
Job.findById(req.params.jobId)
.then((job) => {
if (job != null) {
job.applications.push(req.body);
job.save()
.then((job) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json(job);
})
}
else {
err = new Error('Job ' + req.params.jobId + 'not found')
err.status = 404;
return next(err);
}
}, (err) => next(err))
.catch((err) => next(err));
})
req.body contains following object
{ talentId: '5a813e1eb936ab308c4cae51' }
If you already have the id of the job document then you can push application object direct by doing the following:
Job.update(
{ _id: req.params.jobId },
{ $push: { applications: req.body} },
callback
);
or you can use promise to handle this. and if you are only saving id of the application then you may want to change your job schema to store Id of the applications instead of whole application schema.
Please read the documentation carefully as this is very basic update query.
You have,
talentId: {type: mongoose.Schema.Types.ObjectId,
ref: 'Talent'}
But your req.body contains:
{ talentId: '5a813e1eb936ab308c4cae51' }
It should be:
{ talentId: mongoose.Types.ObjectId('5a813e1eb936ab308c4cae51') }
Turns out there was nothing wrong with code.
I was using import and export default syntax which didn't seem work well with this.
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
and
export default ApplicationSchema;
I replaced them with Common JS syntax and everything worked fine.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
and
module.exports = ApplicationSchema;
I did this for Job document file and every subdocument file and the code worked.

MongoDB - Error: document must have an _id before saving

I've been struggling so much with this project. I am following a tutorial that is out of date in some areas, for instance their version of Jquery used a totally different format for some functions and I had to do a lot of changing around. But I think I am down to one last major problem that I can't seem to find a fix for. In my Schema variable I've got the _id, username, and password types
var UserSchema = new mongoose.Schema({
_id: mongoose.Schema.ObjectId,
username: String,
password: String
});
but when I go to try to add a new user to my app, instead of getting the alert I am supposed to get, it pops up as [object Object] and nothing gets added to the database. Then this error pops up in the mongo cmd
"Error: document must have an _id before saving".
I've tried commenting out the _id line and I get the right message but still nothing shows up in my database.
Its pretty simple:
If you have declared _id field explicitly in schema, you must initialize it explicitly
If you have not declared it in schema, MongoDB will declare and initialize it.
What you can't do, is to have it in the schema but not initialize it. It will throw the error you are talking about
NestJS with mongoose (#nestjs/mongoose) solution
I fixed the error by
Removing #Prop() above _id
Add mongoose.Types.ObjectId as type to _id
import { Prop, Schema, SchemaFactory } from '#nestjs/mongoose';
import mongoose from 'mongoose';
import { Document } from 'mongoose';
export type CompanyDocument = Company & Document;
#Schema()
export class Company {
_id: mongoose.Types.ObjectId;
#Prop({ unique: true })
name: string;
}
export const CompanySchema = SchemaFactory.createForClass(Company);
You can write your model without _id so it will be autogenerated
or
you can use .init() to initialize the document in your DB.
Like:
const mongoose = require('mongoose');
const UserSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
username: String,
password: String
})
module.exports = mongoose.model('User', UserSchema);
and then
const User = require('../models/user');
router.post('/addUser',function(req,res,next){
User.init() // <- document gets generated
const user = new User({
username: req.body.username,
password: req.body.password
})
user.save().then((data)=>{
console.log('save data: ',data)
// what you want to do after saving like res.render
})
}
If you are using mongoose with nest js and GraphQL, I have fixed it by changing the id to _id and removing the #prop above it even the null value of the id problem has vanished. example on github
import { ObjectType, Field, Int, ID } from '#nestjs/graphql';
import { Prop, Schema, SchemaFactory } from '#nestjs/mongoose';
import { Document } from 'mongoose';
import { User } from 'src/user/entities/user.entity';
import * as mongoose from 'mongoose';
export type SchoolDocument = School & Document;
#ObjectType()
#Schema()
export class School {
#Prop()//remove this
#Field(() => ID,{ nullable: true })
_id: string;
#Prop()
#Field(() => String,{ nullable: true })
name: string;
#Field(()=>[User],{nullable:true})
users:User[];
}
export const SchoolSchema= SchemaFactory.createForClass(School);
Try below snippet I wanted to name _id as userId you can do without it as well.
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var UserSchema = new Schema({
username: String,
password: String
});
UserSchema.virtual('userId').get(function(){
return this._id;
});
_id is added automatically by MongoDb.
If you want to keep _id on your data structure be sure to initialize correctly:
import { Types } from "mongoose";
const obj = new UserSchema({
"_id": new Types.ObjectId(),
"username": "Bill",
"password" : "...."
});
In my case, I accidentally had the following at the end of my Schema. Removing that worked:
{ _id: false }
Look the way i fixed was i put just id in json post request and not _id.
No need to specify the document _id in your model. The system generates the id automatically if you leave out the _id like so:
var UserSchema = new mongoose.Schema({
username: String,
password: String
});
That being said, if you still want to generate the _id yourself, see the answers above.

Resources