findByIdAndUpdate keeps being caught in .catch - javascript

So when I am executing my findByIdAndUpdate it doesn't execute my promise as expected and goes into my catch. I sent responses to postman and using res.json(req.user.id) and res.json(profileFields) . This is the response I get when I use
profileFields
{
"user": "5b3134a0e2543b06d130a5d7",
"handle": "wadeaston1",
"status": "Developer",
"skills": [
"HTML",
" CSS",
" Javascipt"
],
"social": {}
}
i'm at a loss here because all my fields are passing in the values as expected into user and $set. I don't understand why its going to my catch
Profile.findByIdAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true }
)
.then(profile => res.json(profile))
.catch(err => {
res.json("Timeout");
console.log("HI");
});
Here is my Profile Schema
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
//Create Scheme
const ProfileSchema = new Schema({
user: {
//this will associate user by their ID
type: Schema.Types.ObjectId,
ref: "users"
},
handle: {
type: String,
required: true,
max: 40
},
company: {
type: String
},
website: {
type: String
},
location: {
type: String
},
status: {
type: String,
required: true
},
skills: {
//Array of strings
type: [String],
required: true
},
bio: {
type: String
},
githubusername: {
type: String
},
experience: [
{
title: {
type: String,
required: true
},
company: {
type: String,
required: true
},
location: {
type: String
},
from: {
type: Date,
required: true
},
to: {
type: Date,
required: true
},
current: {
type: Boolean,
default: false
},
description: {
type: String
}
}
],
education: [
{
school: {
type: String,
required: true
},
degree: {
type: String,
required: true
},
fieldofstudy: {
type: String,
required: true
},
from: {
type: Date,
required: true
},
to: {
type: Date,
required: true
},
current: {
type: Boolean,
default: false
},
description: {
type: String
}
}
],
social: {
youtube: {
type: String
},
twitter: {
type: String
},
facebook: {
type: String
},
linkedin: {
type: String
},
instagram: {
type: String
}
},
date: {
type: Date,
default: Date.now
}
});
module.exports = Profile = mongoose.model("profile", ProfileSchema);

findByIdAndUpdate is for finding the document to update by its _id value, but you need to find the document by its user field, so you should be using findOneAndUpdate instead:
Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true }
)
.then(...
No need to manually cast req.user.id to an ObjectId as Mongoose will do that for you based on the way user is defined in your schema.

Based on the error you gave, it looks like you need to turn req.user.id from a string to an ObjectId:
Profile.findByIdAndUpdate(
{ user: new mongoose.Types.ObjectId(req.user.id) },
{ $set: profileFields },
{ new: true }
).then( /* rest of code */
This assumes you did a const mongoose = require('mongoose') or similar.

Related

Can't filter by a nested populated item

I'm using mongoose-paginate-v2 for my TransactionModel.
I can't seem to filter by the user name or email.
If I don't use any query the docs return with the populated objects, like the user's name, and email, so I believe the issue is with the filter variable.
I want to keep using mongoose-paginate-v2
const transactionSchema: Schema = new Schema(
{
user: { type: Types.ObjectId, ref: CollectionNames.user, required: false },
subscription: { type: Types.ObjectId, ref: CollectionNames.subscription, required: false },
paidAt: { type: Date, required: true, default: new Date() },
amount: { type: Number, required: true },
currency: { type: String, required: true, default: CurrencyCodes.USD },
status: { type: String, required: true, default: TransactionStatuses.pending },
refundedAt: { type: Date, required: false },
refundAmount: { type: Number, required: false },
provider: { type: String, required: true },
providerTransactionId: { type: String, required: true },
invoiceLink: { type: String, required: false },
referral: { type: referralSchema, required: false },
eventsHistory: { type: [String], required: false, default: [] }
},
{
timestamps: true
}
);
// The function body:
const { page, limit, query: searchQuery } = query;
const options = {
page: page || 1,
limit: limit || 10,
sort: {
createdAt: -1
},
populate: [
{
path: 'user',
select: 'name socialAccounts email lastLoginEmail notificationEmail'
},
{
path: 'referral',
select: 'user commission payoutExpectedAt paidAt status'
}
],
lean: true
};
const filter = {};
if (searchQuery) {
const searchQueryRegex = new RegExp(searchQuery, 'i');
Object.assign(filter, {
$or: [
{
providerTransactionId: {
$regex: searchQueryRegex
}
},
{
'user.name': {
$regex: searchQueryRegex
}
},
{
'user.email': {
$regex: searchQueryRegex
}
},
]
});
}
const { docs, totalDocs, totalPages, hasNextPage } = await TransactionModel.paginate(filter, options);

how to get data with $gte $lte

I'm trying to get some datas by mongoose.
let datas =
await Data.find({
'$and': [
{ test_id: testId },
{ createdAt: { $gte: moment(req.query.from).startOf('day') } },
{ createdAt: { $lte: moment(req.query.to).endOf('day') } }
],
});
This is works. But, I try to change aggregate, I can't get any data.
How should I get same result?
const datas = await Data.aggregate([
{
'$match': {
'$and': [
{ test_id: testId },
{ createdAt: { $gte: moment(req.query.from).startOf('day') } },
{ createdAt: { $lte: moment(req.query.to).endOf('day') } }
],
}
}]);
My definition is like this.
const Data = new Schema({
test_id: {
type: String,
required: true,
},
user_id: {
type: String,
required: true,
},
item: {
agent_id: { type: String, ref: 'Company' },
product_no: { type: String, required: true },
user_id: { type: String, required: true, ref: 'User' },
name: { type: String, required: true },
quantity: { type: Number, required: true },1 },
standard_price: { type: Number},
designation: { type: String },
category: { type: String },
weight: { type: Number },
materials: { type: String },
remarks: { type: String },
note: { type: String },
location: String,
image: String
}
}, {
timestamps: true,
});
And when I change the condition only { test_id: testId },
I can get the data. I doubt of term conditions in the aggregate.
But I don't know how to resolve it.
mongoose version is "5.11.15".
"mongoose": "5.11.15",

Looping Over And Array of Objects and Updating Each One

I'm trying to update objects inside an array based on specific conditions that I check using two functions. I couldn't achieve this with the match feature available in mongoose.
As you can see below, I'm trying to loop over the array of posts, send each post and check if it fulfills a condition, then update it using findOneAndUpdate. The functions isLessThanOne and isAchieved return the expected value.
(async () => {
let posts = await Post.find()
posts.map(async (post) => {
if (isLessThanOneDay(post.deadline)) {
console.log(post.id, post._id)
await Post.findOneAndUpdate(post.id, { $set: { category: 'deadline' }})
} else if (isAchieved(post.milestones)) {
await Post.findOneAndUpdate(post.id, { $set: { category: 'achieved' }})
} else {
await Post.findOneAndUpdate(post.id, { $set: { category: 'newGoals' }})
}
})
})()
This is the schema
const { type } = require("express/lib/response")
const mongoose = require("mongoose")
const PostSchema = new mongoose.Schema({
// we have to link or refer each post to a user
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "user",
},
title: {
type: String,
required: true
},
desc: {
type: String
},
milestones: [],
likes: [
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "user"
},
fName: {
type: String,
required: true
},
date: {
type: String,
required: true
}
}
],
comments: [
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "user"
},
text: {
type: String,
required: true
},
fName: {
type: String,
},
date: {
type: String,
}
}
],
rewards: [
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "user"
},
fName: {
type: String,
required: true
},
date: {
type: String,
required: true
},
reward: {
type: String,
required: true
},
price: {
type: Number,
required: true
}
}
],
date: {
type: String,
required: true
},
shares: [
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "user"
},
fName: {
type: String,
required: true
},
date: {
type: String,
required: true
}
}
],
deadline: {
type: String,
required: true
},
category: {
type: String,
}
})
module.exports = Post = mongoose.model('post', PostSchema)
The problem is that I couldn't update the posts and I've already tried using udpate, directly updating it with post.category then save. Any help would appreciated.
Try this:
(async () => {
let posts = await Post.find()
posts.map(async (post) => {
if (isLessThanOneDay(post.deadline)) {
console.log(post.id, post._id)
await Post.findOneAndUpdate({ _id: post.id }, { $set: { category: 'deadline' }})
} else if (isAchieved(post.milestones)) {
await Post.findOneAndUpdate({ _id: post.id }, { $set: { category: 'achieved' }})
} else {
await Post.findOneAndUpdate({ _id: post.id }, { $set: { category: 'newGoals' }})
}
})
})()
If I recall, the filter parameter must be an object.

Nodejs aggregate lookup returns empty array

I have user model
const mongoose = require("mongoose");
const uniqueValidator = require("mongoose-unique-validator");
const userSchema = mongoose.Schema({
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
isEmailVerified: { type: Boolean },
registrationStep: { type: Number, enum: [0,1,2,3]},
regDate: { type: Date },
companyName: { type: String },
oib: { type: String },
telephone: { type: String },
address: { type: String },
city: { type: String },
countryCode: { type: String },
postalCode: { type: String },
userType: { type: String, enum:['firms','drivers','both']},
approved: { type: Boolean },
isAdmin: { type: Boolean }
});
userSchema.plugin(uniqueValidator);
module.exports = mongoose.model("User", userSchema);
and documents model
const mongoose = require("mongoose");
const docsSchema = mongoose.Schema({
docsPath: { type: String, required: true },
creator: { type: mongoose.Schema.Types.ObjectId, ref: "User", required: true },
docType: { type: String, enum:['isr','lmp','pocmr'], required: true }
});
module.exports = mongoose.model("Docs", docsSchema);
I want to join collections so that for every user exists the user_docs field with docs data as in code below. I'm trying to do that with joining _id with creator as it is defined when creating a document
exports.getUsersAndDocs = (req, res, next) => {
const query = User.aggregate([
{
$lookup: {
from: "Docs",
localField: "_id",
foreignField: "creator",
as: "user_docs"
}
}]);
query
.then(fetchedUsers => {
res.status(200).json({
message: "Users fetched successfully!",
users: fetchedUsers,
});
})
.catch(error => {
res.status(500).json({
message: "Fetching users failed!"
});
});
};
I'm recieveing empty user_docs array. Thank you for your help
If someone has the same problem. I solved it by changing
from: "Docs"
to
from: Docs.collection.name

mongo query $near always 0 results

My search Position is the same as the position in the database. The result is an empty array. I expected to get the one element from database, because the distance between both locations is 0.
Mongo Doku $near
Query to find all nearest
Request.find({
address: {
location: {
$near: {
$geometry: {
type: 'Point' ,
coordinates: [8.4821159,49.4705199],
},
$maxDistance: 10000,
$minDistance: 0,
},
},
},
})
Mongoose Model
Edit (add): this.request.index({'address.location': '2dsphere'});
import mongoose from 'mongoose';
const ObjectId = mongoose.Schema.Types.ObjectId;
import {RequestMiddleware} from './RequestMiddleware';
class Request extends mongoose.Schema {
public request: mongoose.Schema;
constructor() {
const RequestSchema = {
title: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
category: {
type: ObjectId,
ref: 'Category',
required: true,
},
created_by: {
type: ObjectId,
ref: 'User',
required: true,
},
address: {
location: {
type: {
type: String,
enum: ['Point'],
default: 'Point',
required: true,
},
coordinates: {
type: [Number],
default: [0, 0],
required: true,
},
},
plz: {
type: String,
required: false,
},
city: {
type: String,
required: false,
},
street: {
type: String,
required: false,
},
street_nr: {
type: String,
required: false,
},
},
time_end: {
type: Date,
required: false,
},
confirmed_helper: {
type: ObjectId,
ref: 'User',
},
helper: [{
helperId: {
type: ObjectId,
ref: 'User',
},
offer_text: {
type: String,
},
}],
};
const request = super(RequestSchema, {
timestamps: {
createdAt: 'created_at',
updatedAt: 'updated_at',
},
});
this.request = request;
this.request.index({'address.location': '2dsphere'});
this.request.plugin(RequestMiddleware);
return this.request;
}
}
export default mongoose.model('Request', new Request());
Database:
You need two things:
2dspere index (probably you already have it):
db.col.createIndex( { "address.location" : "2dsphere" } )
and to modify your query so that it uses the dot notation instead of nested object:
let result = await Request.find({
'address.location': {
$near: {
$geometry: {
type: 'Point',
coordinates: [8.4821159, 49.4705199]
},
$maxDistance: 10000,
$minDistance: 0
}
}
});

Categories