Node/Mongoose Error - Can't use $expr with String - node.js

My goal is to create a query that searches for a partial string in a particular field - from the last index of a nested array in a MongoDB database. My constraint is that I must use a .find() query.
I'm using Mongoose 6.2.9 and MongoDB 5.0.4 - I've developed a query that works perfectly in MongoDB Compass, but Mongoose seems to be having issues with:
(node:48632) UnhandledPromiseRejectionWarning: Error: Can't use $expr with String.
The call I'm trying to make:
findQuery['statuses.schema'] = {
$expr: {
$regexMatch: {
input: {
$arrayElemAt: ['$statuses.schema', -1]
},
regex: "sample|regex|here",
options: 'i'
}
}
};
The issue seems to be placing $statuses.schema inside quotation marks (cast as a string) - but without these quotation marks, I seem to get an error in my GraphQL response (this query is part of a resolver for a GraphQL API) that would lead me further away from a solution:
{
"message": "$statuses is not defined",
"locations": [
{
"line": 2,
"column": 3
}
],
Edit: Added Schema
const statusSchema = mongoose.Schema({
timestamp: { type: String },
status: { type: String },
test: { type: String },
symptom: [symptomSchema],
code: { type: String },
});
const serverSchema = mongoose.Schema({
ipAddress: { type: String },
index: { type: String },
serialNumber: { type: String },
model: { type: String },
configCode: { type: String },
operator: { type: String },
onlineStatus: {type: Boolean, default: false},
repairCount: { type: String },
lastRepair: { type: String },
customer: { type: String },
location: [locationSchema],
inRepair: { type: String },
rack: { type: String },
statuses: [statusSchema],
schema_version: { type: String },
}, { _id: true});
So in short, MongoDB seems to require "$myArray.myField" be a string, but Mongoose cannot handle it being a string when nested under $expr. What am I doing wrong?

Related

Mongoose, update a nested object inside a nested object

i'm trying to update an object that is inside an array that is nested inside an array my schema is the following:
const quizzerSchema = mongoose.Schema(
{
title: {
type: String,
},
imgUrl: {
type: String,
},
SKU: {
type: String,
},
topics: [
{
topicTitle: { type: String },
questions: [
{
section: { type: String },
setup: { type: String },
question: { type: String },
correct: { type: String },
answer: { type: String },
note: { type: String },
questionNumber: { type: String },
a: { type: String },
b: { type: String },
c: { type: String },
d: { type: String },
e: { type: String },
},
],
},
],
},
{
timestamps: true,
}
);
I want to be able to update the values of a specific object that inside the questions array.
I was able to update the object that is inside the topics array, but now I need to go a level deeper
This is how I am updating the first nested level (Object inside topics)
let updateTopic = await Quizzer.findOneAndUpdate(
{ _id: bookid, 'topics._id': topicid },
{
$set: {
'topics.$.topicTitle': topicTitle,
},
}
);
But I don't know how to access a level deeper.
Any help would be super appreciated
You can update specific nested value using arrayFilters as below:
db.collection.update({},
{
$set: {
"topics.$[x].questions.$[y].d": "New_Value"
}
},
{
arrayFilters: [
{
"x.questions": {
$exists: true
}
},
{
"y.c": "2"
}
]
})
Explained:
Define 2x arrayFilters x & y in the arrayFilter section to identify the nested element
Use in the $set part the filters to update the nested field with key "d" in the example
Playground

Mongoose documents find by object _id

I have mongoose model like this:
const ChatRoomSchema = new mongoose.Schema(
{
roomId: {
type: String,
required: true,
},
sender: {
_id: { type: String },
name: { type: String },
dp: { type: String },
},
receiver: {
_id: { type: String },
name: { type: String },
dp: { type: String },
},
},
{
timestamps: true,
}
);
Now i want find documents by this query:
const rooms = await ChatRoom.find({sender: {_id: userId }}) // it return the document if
sender itself a _id,
but its a object.
It returns an empty array. How can I find the document throw the sender object's _id field?

Getting error while sorting the mangoDB collection using Node.js and mangoose

I am getting the following error while fetching the record from MongoDB using Node.js and Mangoose.
Error:
Error: 12-05-2020 08:20:33 - MongoError: Executor error during find command :: caused by :: Sort operation used more than the maximum 33554432 bytes of RAM. Add an index, or specify a smaller limit.
at Connection.<anonymous> (/home/anil/Desktop/new/EdQart_Project/local/edqart-store-setup-api/node_modules/mongodb/lib/core/connection/pool.js:460:61)
I am explaining my code below.
const filters = this._getOrdersFilterParams(req);
const sort = this._getOrdersSortingParams(req);//{"CreatedAt":"desc"}
const orders = await collection.find(filters).sort(sort);
I am explaining my model file below.
const mongoose = require('mongoose'),
Float = require('mongoose-float').loadType(mongoose),
Schema = mongoose.Schema,
{
ORDERS_COLLECTION
} = require('../utils/constants.util');
const ModelOrders = new Schema({
OrderNumber: { type: String },
OrderStatus: { type: String },
OrderType: { type: String },
DispatchPriority: { type: String },
Comments: { type: Array },
Products: { type: Array },
Customer: { type: Object },
TotalDiscount: { type: Object },
TotalShipping: { type: Object },
TotalCoupon: { type: Object },
TotalAmount: { type: Object },
PaymentDetails: { type: Object },
ClientDetails: { type: Object },
FocusSync: { type: Boolean },
IsActive: { type: Boolean }
},
{
timestamps: {
createdAt: 'CreatedAt',
updatedAt: 'UpdatedAt'
},
collection: ORDERS_COLLECTION
}
);
ModelOrders.index({CreatedAt: 1}, { background: true });
module.exports = ModelOrders
I have done the indexing but still that issue is coming. I need to resolve this issue and fetch the record with sorting.

removing a string within nested array mongoose

const AllPostsSchema = new Schema({
user: {
type: Schema.Types.ObjectId,
ref: 'users'
},
posts: [{
postid: {
type: String
},
title: {
type: String
},
category: {
type: String
},
subcategory: {
type: String
}, category: {
type: String
},
description: {
type: String
},
name: {
type: String
},
price: {
type: Number
},
email: {
type: String
},
phonenumber: {
type: Number
},
language: {
type: String
},
make: {
type: String
},
model: {
type: Number
},
odometer: {
type: Number
},
condition: {
type: String
},
state: {
type: String
},
town: {
type: String
},
city: {
type: String
},
links: [{ type: String }],
date: {
type: Date,
default: Date.now
}
}]
})
AllPosts.findOneAndUpdate({ 'user': req.query.userid },
{ $pull: { 'posts': { 'links': req.query.link } } }
)
.then(post => console.log(post))
i need to find a specific user and within that user match the post id then remove one of the links in links array. when I do it like above it removes the whole array instead i want it to remove specific link within links array in posts arrayy.
Each user has one or more than one posts. I need to update a single post of a specific user. if a user wants to delete an image i delete that from amazon s3 then, i need to remove the link from that post link array so it doesnt create broken img tags in the front end.
AllPosts.findOneAndUpdate({ 'user': req.query.userid, 'posts.postid': req.query.postid },
{ $pull: { 'links': req.query.link } }
)
.then(post => console.log(post))
this also didnt work.
Solved. For future reference :
AllPosts.findOneAndUpdate({ 'user': req.query.userid, 'posts.postid': req.query.postid },
{ $pull: { 'posts.$.links': req.query.link } }
)
.then(post => console.log(post))

updateMany and elemMatch in with nested schemas in mongoose (Node.js)

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
}...

Resources