I have a special case where our collection needs to make sure each document is unique based on a combination of the email address, and the sweepstakes_id. I've looked all over, but I can't find how to accomplish this type of validation.
Schema definition:
var submissionSchema = new Schema({
client_id: {
type: Schema.Types.ObjectId,
ref: 'Client',
index: true
},
sweepstakes_id: {
type: Schema.Types.ObjectId,
ref: 'Sweepstakes',
index: true
},
email: {
type: String,
index: true
},
data: {
type: Schema.Types.Mixed,
default: []
}
});
You can enforce that using a unique index that includes both fields:
submissionSchema.index({ email: 1, sweepstakes_id: 1 }, { unique: true });
Related
I have a blog model:
let blogSchema = new mongoose.Schema({
author: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
title: { type: String, required: true, unique: true },
description: { type: String, required: true, unique: true },
content: { type: String, required: true, unique: true },
likes: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
views: { type: Number, default: 0, required: true },
tags: [],
currentState: { type: String, enum: ['draft', 'published'], required: true, default: 'draft' }}, { timestamps: true });
and a user model which I don't think is necessary to show.
When I try querying for a blog with the author matching a list of userids that the current user is following as such:
let blogs = await Blog.find({ author: { $in: blogIds } })
It gives me the error: CastError: Cast to ObjectId failed for value "{ '$in': [ new ObjectId("6359f421fd4678e2eba3ffee") ] }" (type Object) at path "author" for model "Blog"
How do I get the blogs? I've tried using the $or operator but I would have to loop and it doesn't work anyway. The array values in $in is found correctly as shown in the error, it isn't converting properly though.
The blogids array is [ new ObjectId("6359f421fd4678e2eba3ffee") ]. It is dynamic and is an array of userids that the user follows (OOPS, the name isn't clear)
I think there might be problem in your blogIds array.Try to convert all value inside it with mongoose.Types.ObjectId.
const allIds=blogIds.map(item=>mongoose.Types.ObjectId(item));
Then update your find query.
const blogs = await Blog.find({ author: { $in: allIds } });
I am trying to create a basic social media website, with post having different comments, likes, comments also having likes. If the logged in user is the one that made the comment or post, he could be able to delete the post.
So I have to use the deep populate method of mongoose, but the issue I am having is, when the content of the comment is showing, then the name of the user that made that comment is missing.
Post Schema is as follows
content: {
type: String,
required: true
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
// include the array of ids of all comments in this post schema itself
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Comment'
}
],
likes: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Like'
}
]
},{
timestamps: true
});
Like Schema is as follows -
const likeSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.ObjectId
},
// this defines the object id of the liked object
likeable: {
type: mongoose.Schema.ObjectId,
require: true,
refPath: 'onModel'
},
// this field is used for defining the type of the liked object since this is a dynamic reference
onModel: {
type: String,
required: true,
enum: ['Post', 'Comment']
}
}, {
timestamps: true
});
User Schema is as follows -
const userSchema = new mongoose.Schema({
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
name: {
type: String,
required: true
},
avatar: {
type: String
}
}, {
timestamps: true
});
Comment Schema is as follows -
const commentSchema = new mongoose.Schema({
content: {
type: String,
required: true
},
// comment belongs to a user
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
post: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Post'
},
likes: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Like'
}
]
},{
timestamps: true
});
And this is the populate function, on the front end I am trying to display all possible posts with all possible likes and comments, with all the comments also having likes. And obviously the name of the user that made the comment -
let posts = await Post.find({})
.sort('-createdAt')
.populate('user')
.populate({
path: 'comments',
populate: {
path: 'user'
},
populate: {
path: 'likes'
}
}).populate('comments')
.populate('likes');
But in the front end, I am not able to display the User Name that made a particular comment.
Please tell the error.
Example: If I delete a user, I want to also remove all of that users associated comments.
const UserSchema = new Schema(
{
username: {
type: String,
unique: true,
},
email: {
type: String,
unique: true,
},
comments: [
{
type: Schema.Types.ObjectId,
ref: "Comment"
}
],
);
Right now I am removing a user with the .findOneAndDelete method.
I am using the mongoose updateMany() method and I also want to keep it a part of transaction. The documentation shows the example of save() where I can do something like Model.save({session: mySession}) but don't really know how to use it with for example Model.updateMany()
UPDATE:
For example I have two models called SubDomain and Service and they look like this respectively:
SUB-DOMAIN
{
name: {
type: String,
required: true,
},
url: {
type: String,
required: true,
unique: true,
},
services: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Service",
},
],
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
}
SERVICE:
{
name: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
price: { type: Number },
tags: { type: Array },
packages: [
{
name: { type: String, required: true },
description: { type: String, required: true },
price: { type: Number, required: true },
},
],
map: { type: String },
isHidden: {
type: Boolean,
required: true,
default: false,
},
sortingOrder: { type: Number },
isForDomain: { type: Boolean, required: false, default: false },
isForSubDomain: { type: Boolean, required: false, default: false },
subDomains: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "SubDomain",
},
],
}
Now the main field here is the services field in SubDomain and subDomains field in Service.
The complicated part😅:
Whenever the user wants to create new service, I want to $push that service's _id into the array of services of all the subDomains inside that new service
And for that, I am using the updateMany() like this:
const sess = await mongoose.startSession();
sess.startTransaction();
const newService = new Service({
_id: mongoose.Types.ObjectId(),
subDomains: req.body.subDomains
...foo
})
await SubDomain.updateMany(
{ _id: { $in: req.body.subDomains } },
{ $push: { services: newService._id } }
);
The problem starts here, of course I can do:
newService.save({session: sess})
but how do I keep my SubDomain's updateMany in the same transaction (i.e sess)
I know my example is difficult to wrap your head around but I have tried to pick a simplest example rather than copying the exact same code which would have been a lot more difficult
var buyerSchema = new Schema({
cart: [{
id: {
type: Schema.Types.ObjectId,
ref: "product"
},
number: Number
}],
personName: { type: String, required: true, trim: true },
image: { type: String, required: false, trim: true },
email: { type: String, required: true, trim: true }
})
How can i populate the Id field
buyerMdl.findByToken(buyer['token']).populate({path: 'cart', populate: {path : 'id', model : 'product'}})
this particular command is not working for me
First of all make sure your findByToken method returns an instance of find so that you can use .populate() in the chain.
The problem is that you're trying to populate a property which is not referenced. So instead of populating card and then ids in it, you should directly populate cart.ids.
This should work:
buyerMdl
.findByToken(buyer['token'])
.populate({
path: 'cart.id',
model: 'product'
});
Your id is inside card array... So you should use with dot notation to populate id
buyerMdl.findByToken(buyer['token']).populate({ path: 'cart.id' })