Looping Over And Array of Objects and Updating Each One - javascript

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.

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 I can use MongoDB $regex operator into an id stored in another collections field

I am creating a search API and using the $regex operator of MongoDB to filter from search text. But I also want to add a category inside the $or operator. I have a category Id and this is an id of another collection whenever I want to get the category I have to populate the category id. But I want to use the same $regex operator on the category as given below.
Category Schema
const mongoose = require('mongoose');
const categorySchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true
},
slug: {
type: String,
required: true,
unique: true
},
type: {
type: String
},
categoryImage: {
type: String
},
parentId: {
type: String
}
}, {
timestamps: true
})
module.exports = mongoose.model('Category', categorySchema);
Product Shema
const mongoose = require("mongoose");
const productSchema = new mongoose.Schema(
{
name: {
type: String,
required: true,
trim: true,
},
slug: {
type: String,
required: true,
unique: true,
},
price: {
type: Number,
required: true,
},
quantity: {
type: Number,
required: true,
},
description: {
type: String,
required: true,
trim: true,
},
offer: {
type: Number,
},
productPictures: [{ img: { type: String } }],
views: {
type: Number,
min: 0,
default: 0,
required: true
},
ratings: [
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true,
},
rate: {
type: Number,
required: true,
max: 5,
},
reviewTitle: {
type: String,
},
review: {
type: String,
},
reviewImages: [
{
img: String,
},
],
date: {
type: Date,
required: true,
}
},
],
category: {
type: mongoose.Schema.Types.ObjectId,
ref: "Category",
required: true,
},
createdBy: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true,
},
},
{
timestamps: true,
}
);
module.exports = mongoose.model("Product", productSchema);
Search Product Controller
exports.searchProducts = async (req, res) => {
try {
const { page = 1, limit = 20 } = req.query;
const pagination = {
skip: (Number(page) - 1) * Number(limit),
limit: Number(limit),
};
const search = req?.query?.s?.split("+").join("") || "";
const fields = req?.query?.fields?.split(",").join(" ");
const sort = req?.query?.sort?.split(",")?.join(" ");
const { products, matchCount, pageNeeded, showingFrom, showingTo } =
await searchProductsService(search, fields, sort, pagination);
if (products.length === 0) {
return res.status(400).json({ error: "No products found" });
}
res
.status(200)
.json({ products, matchCount, pageNeeded, showingFrom, showingTo });
} catch (error) {
return res.status(400).json({ error: "Something Wen't wrong" });
}
};
Search Product Service (Where I am doing database opearations)
exports.searchProductsService = async (search, fields, sort, pagination) => {
await SearchQuery.updateOne(
{ title: search },
{ $inc: { searchedCount: 1 } },
{ upsert: true }
);
const query = {
$or: [
{ name: { $regex: search, $options: "i" } },
{ description: { $regex: search, $options: "i" } },
],
};
const products = await Product.find(query)
.skip(pagination.skip)
.limit(pagination.limit)
.select(fields || "name productPictures price")
.sort(sort);
const matchCount = await Product.find(query).count();
const pageNeeded = Math.ceil(matchCount / pagination.limit);
const showingFrom = pagination.skip + 1;
const showingTo = pagination.skip + products.length;
return { products, matchCount, pageNeeded, showingFrom, showingTo };
};

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",

Mongoose querying an array of objects

How to querying an array using Mongoose ?
search Schema:
const searchschema = new schema({
yeardate: { type: Number, required: true, min: 1820 },
word: { type: String, required: true, index: true },
user: [{ type: schema.Types.ObjectId, ref: 'User' }] })
user Schema:
const userschema = new schema({
username: { type: String, required: true, unique: true, index: true },//
name: { type: String, default: 'NoName' },
gender: { type: String, default: 'male' }, })
This is the query I have tried but did not work:
searchmodel.paginate({ 'user': { $elemMatch: { gender: 'female' } } }, { page: page, limit: 5, populate: ['user'] }).then(searches => {
if (!searches) {
return res.json({ message: 'there is no search' })
}else {
return res.json(searches)
}
})

findByIdAndUpdate keeps being caught in .catch

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.

Categories