I am working on a gaming app.
In one scenario, I need to find all the documents satisfying the condition in all elements of sub-array(SelectionData).
//Model
import mongoose from 'mongoose';
const User_Selection = mongoose.Schema({
UserSelectionID: { type: String, default: "" },
SelectionData: [
{
_id: false,
match_id: { type: String, default: "" },
selected_option: { type: String, default: "" },
selected_points: { type: Number, default: 0 },
Whether_Points_Calculated: { type: Boolean, default: false },
Points_Collected: { type: Number, default: 0 }
}
],
Opponent_Details: {
USERID: { type: String, default: "" },
DisplayName: { type: String, default: "" }
},
Whether_Final_Points_Calculated: { type: Boolean, default: false },
Total_Game_Points: { type: Number, default: 0 },
Status: { type: Boolean, default: true },
created_at: { type: Date, default: null },
updated_at: { type: Date, default: null }
}, { collection: 'User_Selection' });
export default mongoose.model('User_Selection', User_Selection);
I wish to find all the documents satisfying the condition ("SelectionData.Whether_Points_Calculated" == true) in all array elements.
It shoul be like this
const cursor = async() => {
return new Promise((resolve, reject) => {
User_Selection.find({
SelectionData: { Whether_Points_Calculated: true }
})
. then(result => {
resolve(result)
})
. catch(err => {
reject(err)
})
}
This must work:
db.getCollection('User_Selection').find({"SelectionData":{"$elemMatch":{"Whether_Points_Calculated": true}}})
The below script worked for me.
db.collection.find({
"SelectionData": {
"$not": {
"$elemMatch": {
"Whether_Points_Calculated": {
"$eq": false
}
}
}
}
})
playground link
db.collection.aggregate([
{"$match":{"cards":{"$exists":true}}},
{$project: {
"output": {$filter: {
input: '$cards' ,
as: 'arrayElement',
cond: {"$and":[{$eq: ['$$arrayElement.Whether_Points_Calculated', true]}]}
}}
}}
])
Related
I'm quiet new to mongodb and I'm actually trying to implement a follow-unfollow method in the backend
there are two types of users in the database
Mentors and mentees
only mentees can follow the mentors and mentors can only accept the request
the schema
Mentors
const MentorsSchema = mongoose.Schema({
name: { type: String, required: true },
designation: { type: String, required: true },
yearNdClass: {
type: String,
required: ["true", "year and class must be spciefied"],
},
respondIn: { type: String, required: true },
tags: {
type: [String],
validate: (v) => v == null || v.length > 0,
},
socialLinks: {
github: { type: String, default: "" },
twitter: { type: String, default: "" },
facebook: { type: String, default: "" },
instagram: { type: String, default: "" },
},
watNum: { type: Number, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
about: { type: String },
followers: [
{ type: mongoose.Schema.Types.ObjectId, ref: "Mentees", default: "" },
],
pending: [
{ type: mongoose.Schema.Types.ObjectId, ref: "Mentees", default: "" },
],
});
Mentee
const MenteeSchema = mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
yearNdClass: {
type: String,
required: ["true", "year and class must be spciefied"],
},
socialLinks: {
github: { type: String },
twitter: { type: String },
facebook: { type: String },
instagram: { type: String },
},
about: { type: String },
skillLooksFor: { type: String, required: true },
watNum: { type: Number, required: true },
following: [{ type: mongoose.Schema.Types.ObjectId, ref: "Mentors",default:"" },
],
});
you can see that there are two fields for mentors both following and pending arrays which consist of the ids of the mentees who follow the mentors and the ids of the mentees which yet to be accepted as a follower
I planned to create an endpoint where when a mentee gives a follow request it should be reached into the mentor pending array so that he can accept it later
so my logic like this
// #desc follow a mentor
// #route POST /api/mentees/follow-mentor/:id
// #access private
menteeRoute.post(
"/follow-mentor/:id",
isAuthorisedMentee,
expressAsyncHandler(async (req, res) => {
const { id } = req.params;
const mentee = await Mentees.findById(req.mentee.id);
const mentor = await Mentors.findById(id).select("-password");
// console.log(mentor)
if (mentee) {
try {
await Mentees.findOneAndUpdate(
{ _id: mongoose.Types.ObjectId(id) },
{ $addToSet: { "following.0": mentor._id } },
{ new: true }
);
await Mentors.findOneAndUpdate(
{ _id: mongoose.Types.ObjectId(mentor._id) },
{
$addToSet: {
"pending.0": id,
},
},
{ new: true },
);
res.json({
data: {
mentor,
mentee,
},
});
} catch (error) {
console.log(error);
throw new Error(error);
}
}
})
);
but the code didn't work.
can anyone help me to resolve the problem?
basically, when a mentee gives a follow request it should update the following array of mentee with the id of mentor and it should also update the pending array of mentor with the id of the mentee
PS: any alternative ideas are also welcome
Try to remove the .0 index and use the $push method.
Also, you should return the updated objects:
menteeRoute.post(
'/follow-mentor/:id',
isAuthorisedMentee,
expressAsyncHandler(async (req, res) => {
const { id } = req.params;
const mentee = await Mentees.findById(req.mentee.id);
const mentor = await Mentors.findById(id).select('-password');
// console.log(mentor)
if (mentee) {
try {
const updatedMentee = await Mentees.findOneAndUpdate(
{ _id: mongoose.Types.ObjectId(id) },
{ $push: { following: mentor._id } },
{ new: true }
);
const updatedMentor = await Mentors.findOneAndUpdate(
{ _id: mentor._id },
{
$push: {
pending: id,
},
},
{ new: true }
);
res.json({
data: {
mentor: updatedMentor,
mentee: updatedMentee,
},
});
} catch (error) {
console.log(error);
throw new Error(error);
}
}
})
);
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 } },
...
)
Consider :
EightWeekGamePlan.aggregate(
[
{ $match: { LeadId: { $in: leads }, Week: week,
// total: { $lt: 5 } // This part doesn't work
} },
{
$group: {
_id: {
LeadId: "$LeadId",
total: { $sum: "$TotalClaimsLeftToBeClaimedByClientType" }
}
}
}
]
How can I pick all the documents that their sum of $TotalClaimsLeftToBeClaimedByClientType is less than 5 ?
I've tried with total: { $lt: 5 }but I got an empty array.
Here is the Schema :
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const EightWeekGamePlanSchema = new Schema({
Week: {
type: Number,
required: true
},
LeadId: {
type: String,
required: true
},
PackageId: {
type: String,
required: true
},
BusinessName: {
type: String,
required: true
},
PhoneNumberMasque: {
type: String,
required: true
},
City: {
type: String,
required: true
},
Rooms: {
type: Number,
required: true
},
LeadStartDate: {
type: Date
},
LeadEndDate: {
type: Date
},
TargetedToBeClaimedByClientType: {
type: Number,
required: true
},
TotalClaimsLeftToBeClaimedByClientType: {
// incresed by 1 every time it's claimed
type: Number,
required: true
},
TotalClaimsToBeClaimedByClientType: {
// Stays fixed
type: Number,
required: true
},
Status: {
type: Number,
required: true
},
InsertDate: {
type: Date,
default: Date.now
}
});
module.exports = EightWeekGamePlan = mongoose.model(
"eightweekgameplan",
EightWeekGamePlanSchema
);
From your query, try this :
EightWeekGamePlan.aggregate(
[
{
$match: {
LeadId: { $in: leads }, Week: week
}
},
{
$group: {
_id: {
LeadId: "$LeadId",
total: { $sum: "$TotalClaimsLeftToBeClaimedByClientType" }
}
}
}, {
$match: {
'_id.total': { $lte: 5 }
}
}
])
From the above it $match did not work because your total is not a top level field, it's inside _id. So it's basically grouped based on LeadId + sum of TotalClaimsLeftToBeClaimedByClientType. Just in case if you wanted to group only based on LeadId check below one.
(Or) you can change the query :
EightWeekGamePlan.aggregate(
[
{
$match: {
LeadId: { $in: leads }, Week: week
}
},
{
$group: {
_id: {
LeadId: "$LeadId"
},
total: { $sum: "$TotalClaimsLeftToBeClaimedByClientType" }
}
}, {
$match: {
'total': { $lte: 5 }
}
}
])
I am using comment array in my schema as fallows. I want to push comments data into that comment array using nodejs api
var Schema = mongoose.Schema;
var myfeeds = new Schema({
title: {
type: String,
required: true
},
feed: {
type: String,
required: true
},
createdBy: {
type: String,
required: true,
unique: true
},
createdDate: {
type: Date,
required: true,
default: Date.now()
},
comment: [
{
commentBy: {
type: String
},
commentText: {
type: String
},
createdDate: {
type: Date
}
}
],
likes: [
{
likesCount: {
type: Number,
required: false
},
likeBy: {
type: String,
required: false
}
}
]
});
I want to push object to this comment array. so, for that I did in this way please tell me if anything wrong in this
let _id = req.body.id;
let commentBy = req.body.commentedBy;
let commentedText = req.body.commentedText;
let commentedDate = req.body.commentedDate;
let data = {
commentBy: commentBy,
commentText: commentedText,
createdDate: commentedDate
};
MyFeeds.findByIdAndUpdate(
{ _id: _id },
{
$push: {
comment: data
}
}
)
.then((result) => {
res.status(200).json({
status: result
});
})
.catch((err) => {
res.status(500).json({
status: 'invalid',
err: err
});
});
but only id are inserted into that comment array but not the required content
"comment": [
{
"_id": "5badfd092b73fa14f4f0aa7c"
},
{
"_id": "5badfd102b73fa14f4f0aa7d"
},
{
"_id": "5badfd142b73fa14f4f0aa7e"
},
{
"_id": "5badfd31500fb11bb06b4c8a"
},
{
"_id": "5badfd35500fb11bb06b4c8b"
},
{
"_id": "5badff3d439a151190d62961"
}
],
I have tried updating other fields and it works just fine.
The command I am using in my API:
User.update({ email: targetUser.email }, { $set: { isAdmin: true }, $push: { 'log.updated': new Date() } }, function (err, user) {
if (err) {
responseObject.err = err;
responseObject.data = null;
responseObject.code = 422;
return res.json(responseObject);
}
return res.json(responseObject);
});
To clarify, when I try to run this, the API returns a code 200, meaning everything worked fine, but when I check the database the isAdmin value wasn't changed.
Any suggestions would be helpful, running out of ideas here!
User Schema as requested:
var UserSchema = new Schema({
name: { type: String, default: "", index: 'text' },
email: { type: String, lowercase: true },
role: { type: String, default: "" },
meta: {
skills: { type: Array, default: [], index: 'text' },
about: { type: String, default: "", index: 'text' },
education: { type: Array, default: [], index: 'text' },
location: {
address: {
a: { type: String, default: "" },
p: { type: String, default: "" },
c: { type: String, default: "" }
},
geo: {
lat: { type: Number, default: 0 },
lng: { type: Number, default: 0 }
}
}
},
compMeta:
{
departments: { type: Array, default: [], index: 'text' },
employees:
[
{
emId: Number,
empName: String,
empDep: String // Dunno if i should use Dep name or Dep ID gonna look in to that later
}
],
}
,
settings: {
search: {
distance: {
n: { type: Number, default: 100 },
t: { type: String, default: "km" }
}
}
},
created: {
type: Date,
default: Date.now
},
//Rating is an array of objects that consist of rateing 0-100 , job database id , comments from the Company
rating:
[
{
rate: Number,
jobId: Number,
jobComments: String
}
],
/*rating:
{
userTotalRating: {type: Number, default: 0},
ratingCounter : {type: Number, default: 0}
}*/
sensitive: {
cpr_cvr: String,
},
stripe: { type: String },
facebook: {},
linkedin: {},
log: {
updated: { type: Array, default: [] }
},
hashedPassword: String,
provider: { type: String, default: 'local' },
salt: String
});
UPDATE:
Mongodb version: 3.0.7
Turns out I just forgot to add the isAdmin field to my User Schema! Also, my call to the update was wrong, I changed it to this:
User.update({ email: targetUser.email }, { $set: { isAdmin: true }}, { $push: { 'log.updated': new Date() } }, function (err, user) {
if (err) {
responseObject.err = err;
responseObject.data = null;
responseObject.code = 422;
return res.json(responseObject);
}
return res.json(responseObject);
});
Thanks to everyone that put an effort to help me! :)
I encountered a similar problem. The solution was to add the callback.
This doesn't work:
Ride.updateOne({driver:req.body.id},{$set:{isBusy:true}});
This works:
Ride.updateOne({driver:req.body.id},{$set:{isBusy:true}},(e,s)=>{});
Try updating two fields with $set
User.update({ email: targetUser.email }, { $set: { isAdmin: true, 'log.updated': new Date() } }, function (err, user) {
if (err) {
responseObject.err = err;
responseObject.data = null;
responseObject.code = 422;
return res.json(responseObject);
}
return res.json(responseObject);
});
Hope it's works.
There is easier way to handle the issue. As per the documentation, the second parameter is the object where you can update the statement.
A.findByIdAndUpdate(id, update, options, callback)
So you just need to take everything inside the update object.
User.update({ email: targetUser.email, $set: {isAdmin: true}} // ... etc