Reputation: 2145
I have a Mongo collection of Users and a collection of Addresses. Each address is owned by one user.Here are my schema classes:
export type UserDocument = User & mongoose.Document
@Schema({ timestamps: true })
export class User {
// @Prop({ type: mongoose.Types.ObjectId })
_id: string
@Prop({ required: true })
name: string
@Prop({ required: true, unique: true })
email: string
@Prop({ select: false })
password: string
}
export const UserSchema = SchemaFactory.createForClass(User)
export type AddressDocument = Address & Document
@Schema({ timestamps: true })
export class Address {
@Prop({ type: mongoose.Schema.Types.ObjectId, ref: User.name })
user: User
@Prop()
line1: string
@Prop()
line2?: string
@Prop()
city: string
@Prop()
state?: string
@Prop()
country: string
}
export const AddressSchema = SchemaFactory.createForClass(Address)
Then I have an AddressService that can fetch addresses for a user:
@Injectable()
export class AddressService {
constructor(@InjectModel(Address.name) private addressModel: Model<AddressDocument>) {}
async save(address: AddressDto): Promise<Address> {
const model = await this.addressModel.create(address)
return model.save()
}
async findAddressForUser(userId: string) {
const userObjectId = new mongoose.Types.ObjectId(userId)
const users = await this.addressModel.find({ user: userObjectId })
}
}
This code has an error: Type '_ObjectId' is not assignable to type 'Condition<User>
I tried passing the userId as a string as well, that did not work either.
What is the right way to query a collection using a reference Id from another collection?
Upvotes: 18
Views: 38355
Reputation: 485
In my case, after reviewing all of your answer, i saw that i had already resolved the question by a certain way somewhere in my app.
So basically what work on my side:
@ObjectType()
export class Account implement AccountInterface{
...some properties
//to manage Parent relation
@Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'User' })
owner: User;
//to manage Children relation
@Prop([{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }])
users?: [User];
}
My AccountInterface
export interface AccountInterface {
//some properties
owner: User;
users: [Users]
}
seems to work without problem.
const account = await this.accountModel.find({
owner: user._id,
});
However you need to define the way data should be fetch from parent and children. The answer above from EzPizza appears to be the best way to handle relationship.
Upvotes: 0
Reputation: 21
The following code worked:
async findModulesUser(id: string) {
const record = await this.modulesuserModel
.find({ user: new Types.ObjectId(id) })
.populate("user", ["name", "email"])
.exec();
return record;
}
Upvotes: 2
Reputation: 1150
I think the user
field shouldn't be of type User
, despite what the NestJS docs say. It should be of type Types.ObjectId
.
Something like this (with cleaner imports aswell):
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { SchemaTypes, Types, Document } from 'mongoose';
export type AddressDocument = Address & Document
@Schema({ timestamps: true })
export class Address {
@Prop({ type: SchemaTypes.ObjectId, ref: User.name })
user: Types.ObjectId;
...
}
export const UserSchema = SchemaFactory.createForClass(User)
I got this from here.
You could also tell TypeScript that this may be either a string, an ObjectId or a User by declaring it as: user: string | Types.ObjectId | UserDocument;
Upvotes: 18
Reputation: 2145
Not sure if this is the proper way of doing this but this is what I ended up doing to get around that error:
async findAddressForUser(userId: string): Promise<Address[]> {
const query: any = { user: new mongoose.Types.ObjectId(userId) }
return await this.addressModel.find(query).exec()
}
Upvotes: 8