I'm trying to query a MongoDB database via mongoose to updateMany the fields of my database. I suppose that the first request is correct because mongoose doesn't fire any error, but for the nested schemas, I'm getting the following error.
My goal is to delete the occurences of the userTag in friends and remove the friendRequestsSent when userTarget equals userTag, friendRequestsReceived when userRequest equals userTag and notification when data equals userTag.
Here are the schemas of my Model
const NotificationSchema = new Schema({
title: String,
type: Number,
icon: String,
data: String,
createdAt: { type: Date, default: Date.now },
})
const FriendRequestSchema = new Schema({
userRequest: { type: String, required: true },
userTarget: { type: String, required: true },
createdAt: { type: Date, default: Date.now },
})
const UserSchema = new Schema({
tag: { type: String, required: true, unique: true },
friendRequestsSent: { type: [FriendRequestSchema] },
friendRequestsReceived: { type: [FriendRequestSchema] },
friends: { type: [String] },
notifications: { type: [NotificationSchema] },
})
The request
const updateResponse = await User.updateMany(
{
friends: { $elemMatch: { $eq: userTag } },
friendRequestsSent: {
userTarget: {
$elemMatch: { $eq: userTag },
},
},
friendRequestsReceived: {
userRequest: {
$elemMatch: { $eq: userTag },
},
},
notifications: {
data: {
$elemMatch: { $eq: userTag },
},
},
},
{
$pull: {
friends: userTag,
friendRequestsSent: { userTarget: userTag },
friendRequestsReceived: { userRequest: userTag },
notifications: { data: userTag },
},
}
)
The error
Error while deleting the user account: Cast to String failed for value "{ '$elemMatch': { '$eq': '0eQzaAwpt' } }" at path "userRequest" for model "User"
The userRequest field in friendRequestsReceived is type String, not array so $elemMatch will not work. Also, you don't need to use $elemMatch because you specify only a single condition in the $elemMatch expression as it says in the docs:
If you specify only a single condition in the $elemMatch expression, you do not need to use $elemMatch.
In your case, you just need to do something like (details here):
await User.updateMany({
friends: userTag,
"friendRequestsSent.userTarget" : userTag,
"friendRequestsReceived.userRequest": userTag,
"notifications.data": userTag
}...
Related
This is my shema in mongoose
import {Schema, model} from 'mongoose'
const EmployeeSchema = new Schema({
employeeCode: {
type: String,
},
name: {
type: String,
},
appraisal: {
status: {
type: String,
enum: ["not started", "in progress", "completed", "not started", "self rating"],
default: "not started"
},
objective_group: [{
name: {
type: Schema.Types.ObjectId,
ref: "ObjectiveGroup",
required: true
},
value: {
type: Number,
},
objective_type: [{
name: {
type: Schema.Types.ObjectId,
ref: "ObjectiveType",
required: true
},
value: {
type: Number,
},
objective_description: [{
name: {
type: Schema.Types.ObjectId,
ref: "ObjectiveDescription",
required: true
},
value: {
type: Number,
},
ratings: {
type: {
type: Schema.Types.ObjectId,
ref: "Ratings",
}
},
}],
training_recommendation: {
type: Schema.Types.ObjectId,
ref: 'TrainingRecommendation'
},
other_recommendation: {
type: Schema.Types.ObjectId,
ref: 'OtherRecommendation'
},
}],
}],
},
})
export default model('Employee', EmployeeSchema)
Here is my code for the following task
const updateValue = asyncHandler(async (req: Request, res: Response) => {
const {id, rating} = req.body
const employee = await Employee.findOneAndUpdate({
"_id": "6204935ebca89023952f2da9",
"appraisal.objective_group._id": "6207ec6a8bfc1226d3f36fb1"
},
{
$set: {
"appraisal.$[objective_group].value": 1234
}
},
{
arrayFilters: [
{
'objective_group._id': new mongoose.Types.ObjectId("6207ec6a8bfc1226d3f36fb1")
}
]
}
)
res.status(StatusCodes.OK).json({
employee
});
})
Here I am trying to update the value field in objective_group. To achieve this I am using arrayfilter. But I am getting this Error
Error: Could not find path "appraisal.0._id" in schema
When I am mongoose v6 it's showing this error. on mongoose v5 I am not getting any errors but the operation is not succeeding
There is the possibility that I am not using arrayfilters in the right way because inside objective_group I am storing objects inside the array.
I am new to StackOverflow so sorry for some mistakes
You just have a slight error with the path you're providing, the error means that the path you gave resolved into a none array value.
You just need to change your update part from:
"appraisal.$[objective_group].value": 1234
To:
"appraisal.objective_group.$[objective_group].value": 1234
Like so:
db.collection.update({
"_id": "6204935ebca89023952f2da9",
"appraisal.objective_group._id": ObjectId("6207ec6a8bfc1226d3f36fb1")
},
{
$set: {
"appraisal.objective_group.$[group].value": 1234
}
},
{
arrayFilters: [
{
"group._id": ObjectId("6207ec6a8bfc1226d3f36fb1")
}
]
})
Mongo Playground
how can I update many orderStatus instead of only one?
request.body.type is by default string and contains only one type;
and when isCompleted for the type go true I want even for previous enum index isCompleted go true
is it possible or do I need to modify it in the front-end?
here is the code
const orderSchema = new mongoose.Schema(
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true,
},
orderStatus: [
{
type: {
type: String,
enum: ["ordered", "packed", "shipped", "delivered"],
default: "ordered",
},
date: {
type: Date,
},
isCompleted: {
type: Boolean,
default: false,
},
},
],
}
exports.updateOrder = (req, res) => {
Order.updateOne(
{ _id: req.body.orderId, "orderStatus.type": req.body.type },
{
$set: {
"orderStatus.$": [
{ type: req.body.type, date: new Date(), isCompleted: true },
],
},
}
).exec((error, order) => {
Hey You can use updateMany() operation
db.collection.updateMany(
<query>,
{ $set: { status: "D" }, $inc: { quantity: 2 } },
...
)
Graphql query returns id null (in frontend) after mongodb aggregation, but if I print a console.log in the resolvers aggregation, _id is not null. I don't know why in the backend I have a id and in front is null. Anybody can help me? Thanks
Client Schema
const ClientSchema = mongoose.Schema({
surname: {
type: String,
require: true,
trim: true
},
company: {
type: String,
require: true,
trim: true
},
salesman: {
type: mongoose.Schema.Types.ObjectId,
require: true,
ref: 'User'
}
})
module.exports = mongoose.model('Client', ClientSchema)
Order Schema
const OrderSchema = mongoose.Schema({
order: {
type: Array,
require: true,
},
total: {
type: Number,
require: true,
},
client: {
type: mongoose.Schema.Types.ObjectId,
require: true,
ref: 'Client'
},
salesman: {
type: mongoose.Schema.Types.ObjectId,
require: true,
ref: 'User'
},
stage: {
type: String,
default: "PENDENT"
},
})
module.exports = mongoose.model('Order', OrderSchema)
Resolver
getOrdersBySalesman: async (_, { }, ctx) => {
const mongoObjectId = mongoose.Types.ObjectId(ctx.user.id);
try {
const orders = await Order.aggregate([
{ $match: { salesman: mongoObjectId }},
{ $lookup: {
localField: "client",
foreignField: "_id",
from: "clients",
as: "client"
}},
{ $unwind: '$client' },
{ $sort: { 'client.company': 1 }}
]);
console.log(orders);
return orders;
} catch (error) {
console.log(error);
}
}
Graphql query
const GET_ORDERS = gql`
query getOrdersBySalesman {
getOrdersBySalesman {
id
order{
name
quantity
}
total
client {
id
surname
company
}
stage
}
}`
Result console.log resolver _id is fine
{ _id: 5ee0da703b683e071c0adfe2,
order: [ [Object] ],
stage: 'PENDENT',
total: 6166.65,
client:
{ _id: 5ea813b3085b4417b8627557,
surname: 'NOU2',
company: 'NN',
salesman: 5ea568905d47ed2760e8d11c,
__v: 0 },
salesman: 5ea568905d47ed2760e8d11c,
__v: 0 } ]
Result in frontend after graphql query id: null
{ id: null,
order: [{…}]
stage: 'PENDENT',
total: 6166.65,
client:
{ id: null,
surname: 'NOU2',
company: 'NN',
}
}
Use type ID for your id in GraphQL Schema as long as you are returning ObjectID and it should work just fine.
type Order {
id: ID
...
}
I have a Mongoose model called Session with a field named course (Course model) and I want to perform full text search on sessions with full text search, also I wanna aggregate results using fields from course sub field and to select some fields like course, date, etc.
I tried the following:
Session.aggregate(
[
{
$match: { $text: { $search: 'web' } }
},
{ $unwind: '$course' },
{
$project: {
course: '$course',
date: '$date',
address: '$address',
available: '$available'
}
},
{
$group: {
_id: { title: '$course.title', category: '$course.courseCategory', language: '$course.language' }
}
}
],
function(err, result) {
if (err) {
console.error(err);
} else {
Session.deepPopulate(result, 'course course.trainer
course.courseCategory', function(err, sessions) {
res.json(sessions);
});
}
}
);
My models:
Session
schema = new mongoose.Schema(
{
date: {
type: Date,
required: true
},
course: {
type: mongoose.Schema.Types.ObjectId,
ref: 'course',
required: true
},
palnning: {
type: [Schedule]
},
attachments: {
type: [Attachment]
},
topics: {
type: [Topic]
},
trainer: {
type: mongoose.Schema.Types.ObjectId,
ref: 'trainer'
},
trainingCompany: {
type: mongoose.Schema.Types.ObjectId,
ref: 'training-company'
},
address: {
type: Address
},
quizzes: {
type: [mongoose.Schema.Types.ObjectId],
ref: 'quiz'
},
path: {
type: String
},
limitPlaces: {
type: Number
},
status: {
type: String
},
available: {
type: Boolean,
default: true
},
createdAt: {
type: Date,
default: new Date()
},
updatedAt: {
type: Date
}
},
{
versionKey: false
}
);
Course
let schema = new mongoose.Schema(
{
title: {
type: String,
required: true
},
description: {
type: String
},
shortDescription: {
type: String
},
duration: {
type: Duration
},
slug: {
type: String
},
slugs: {
type: [String]
},
program: {
content: {
type: String
},
file: {
type: String
}
},
audience: [String],
requirements: [String],
language: {
type: String,
enum: languages
},
price: {
type: Number
},
sections: [Section],
attachments: {
type: [Attachment]
},
tags: [String],
courseCategory: {
type: mongoose.Schema.Types.ObjectId,
ref: 'course-category',
required: true
},
trainer: {
type: mongoose.Schema.Types.ObjectId,
ref: 'trainer'
},
trainingCompany: {
type: mongoose.Schema.Types.ObjectId,
ref: 'training-company'
},
status: {
type: String,
default: 'draft',
enum: courseStatus
},
path: {
type: String
},
cover: {
type: String,
required: true
},
duration: {
type: Number,
min: 1
},
createdAt: {
type: Date,
default: Date.now
},
updatedAt: {
type: Date
}
},
{ versionKey: false }
);
I am not sure if what I tried is gonna bring me what I want and I am getting this error concerning the $unwind operator:
MongoError: exception: Value at end of $unwind field path '$course'
must be an Array, but is a OID
Any kind of help will be really appreciated.
You can try below aggregation.
You are missing $lookup required to pull course document by joining on course object id from session document to id in the course document.
$project stage to keep the desired fields in the output.
Session.aggregate([
{
"$match": {
"$text": {
"$search": "web"
}
}
},
{
"$lookup": {
"from": "courses",
"localField": "course",
"foreignField": "_id",
"as": "course"
}
},
{
"$project": {
"course": 1,
"date": 1,
"address": 1,
"available": 1
}
}
])
Course is an array with one course document. You can use the $arrayElemAt to project the document.
"course": {"$arrayElemAt":["$course", 0]}
I am trying to delete one array element when I click delete button on jade view page.
When clicked, it's going to send selected instructor objected as req.body.
At sever side, it will find courses that contain the instructor objectId.
Any idea for me?
Thank you for reading it.
here is my code:
var id = req.body._id;
clist.find({ instructors: { $in: [id] } }).exec(function (err, result) {
result.forEach(function (obj) {
clist.update(
{ _id: new mongoose.Types.ObjectId(obj._id)},
{ $pull: { instructors : [new mongoose.Types.ObjectId(id)] } }
);
console.log(new mongoose.Types.ObjectId(obj._id) + ' was deleted');
});
});
Schema Clist and ilist:
var instructorlist = mongoose.Schema({
name: { type: String, required: true },
age: { type: Number, required: true },
gender: { type: String, required: true },
DOB: { type: Date, required: true, default: Date.now },
email: { type: String, required: true },
phone: { type: Number, required: true },
address: { type: String, required: true },
dateofstart: { type: Date, required: true},
courses: [{
type: mongoose.Schema.Types.ObjectId,
ref: "clist"
}]
});
var courselist = mongoose.Schema({
coursename: { type: String, required: true },
coursenumber: { type: String, required: true },
coursecredit: { type: Number, required: true },
courseroom: { type: String, required: false },
courseregisteddate: {type: Date, default: Date.now},
students: [{
type: mongoose.Schema.Types.ObjectId,
ref: "slist"
}],
instructors: [{
type: mongoose.Schema.Types.ObjectId,
ref: "ilist"
}]
});
one example for mongodb :
{
"_id": {
"$oid": "591a7a3b391a1842e8a69e23"
},
"coursename": "JDKD",
"coursenumber": "COMP4483",
"coursecredit": 4,
"courseroom": "sdaf",
"instructors": [
{
"$oid": "591a374422a3a13d38c0bbe5"
}
],
"students": [],
"courseregisteddate": {
"$date": "2017-05-16T04:04:11.848Z"
},
"__v": 0
}
When I add instructor objectID in Course.
var newcourse = new clist({
'coursename': req.body.coursename, 'coursenumber': req.body.coursenumber, 'coursecredit': req.body.coursecredit
, 'courseroom': req.body.room, 'instructors': instructors._id
});
Use same operation to find and update multiple
clist.update(
{ instructors: { $in: [id] }},
{ $pull: { instructors : { _id : new mongoose.Types.ObjectId(id) } } }, //or{ $pull: { instructors: mongoose.Types.ObjectId(id) } }
{
multi:true
},
function(error, success){
if(error){
console.log("error",error)
}
console.log("success",success)
});