I'm trying to get the userid, and the array object that contains the specific location within locations.
What I want to accomplish is the following:
The query will return the array location's result.
If not userid exist at all, create it, then return the array of the matching location.
If the location id Number is not there. create a new one, then return the array of the matching location.
How can I accomplish this?
Current query:
easyCrime.findOne({
userid: userid,
"locations.location": location
}, {"locations.$.location": 1}).then(function (err, stats) {
}
});
model:
userid: {
type: String,
default: '57c1c0f3b6b20c011242bf22'
},
locations: [
{
userid: {
type: String,
default: '57c1c0f3b6b20c011242bf22'
},
location: {
type: Number,
default: 1
},
easycrime: [
{
optioname : {
type: String,
default: 'unknown'
},
chance: {
type: Number,
default: 500
}
}
],
heavycrime: [
{
optioname : {
type: String,
default: 'unknown'
},
chance: {
type: Number,
default: 500
}
}
],
}
],
timesteal: {
type:Number,
default: 0
}
I presume that easyCrime is Model, cause there is no such thing as findOne query in a Document. If it is a Model please name it EasyCrime.
I had a really hard time interpreting your question. Base on what I understand, this is your solution
EasyCrime
.findOne({ userid: param.userid})
.exec((err, crime) => {
//userid not exists at all, create new
if (!crime) {
let newCrime = new EasyCrime({...});
newCrime.save(...);
return;
}
//Check if location exists
for (let i = 0; i < crime.locations.length; ++i) {
if (crime.locations[i].location === param.location) {
//crime.location[i] is what you're finding
return;
}
}
//Cannot find any location with provided param.location
crime.locations.push({
userid: ...,
location: param.location,
...
});
crime.save(...);
})
Related
I have a Schema that holds an array of objects for comments and I would like to update the boolean value of the flagged comments accordingly, I have tried updateOne and aggregate but it isn't working out at this point, I have also tried to use $elemMatch but it isn't working.
The comment _id is being pulled from the front end element that has an ID that is the same as the id that needs to be pulled from MongoDB.
Comments Array within the question Schema:
comments: [
{
user: {
type: Object,
},
commentDate: {
type: Date,
default: Date.now()
},
flagged: {
type: Boolean,
default: false
},
flaggedDate:{type: Date},
comment: String,
}
],
function I tried to run last.
const id = req.params.id
const updateFlag = Question.updateOne(
{
comments: [
{
_id: id
}
]
},
{
$set: {
comments: [
{
flagged: req.body.flagged
}
]
}
}
)
Any help would be appreciated!
You can do it with positional operator - $:
db.collection.update({
"comments._id": "3"
},
{
"$set": {
"comments.$.flagged": true
}
})
Working example
I have an array of reviews, I want to add a review using addToSet that will check if user is present in the array, then we do not want to add since one user can only review once.
My schema looks like this:
const sellerSchema = new mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
unique: true,
},
reviews: [
{
by: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
unique: true,
},
title: {
type: String,
},
message: {
type: String,
},
rating: Number,
imagesUri: [{ String }],
timestamp: {
type: Date,
default: Date.now,
},
},
],
});
I might be doing the query wrong, but can't figure out how to add a review and check if current user has not reviewed before.
Here is the query where I add the review:
router.post("/review/:_id/", async (req, res) => {
try {
const stylist_id = mongoose.Types.ObjectId(req.params._id);
const review = {
by: req.user._id,
title: req.body.title,
message: req.body.message,
rating: parseFloat(req.body.rating),
};
if (req.body.imagesUri) {
//if there is images, we need to set it up
review.imagesUri = req.body.imagesUri;
}
await Seller.updateOne(
{ _id: seller_id },
{ $addToSet: { reviews: review } } //get the review that matches to the user_id
);
return res.status(200).send(true);
}catch(err){
res.status(502).send({
error: "Error creating a review.",
});
}
});
I'm thinking of checking for seller's id and also check that no review is by current user, but it is not working.
const userID = req.user._id;
await Seller.updateOne(
{ _id: seller_id, reviews: { $elemMatch: { by: { $ne: { userID } } } } },
{ $addToSet: { reviews: review } } //get the review that matches to the user_id
);
ANSWER:
I was able to solve the issue, in case other people have same issue. I did this:
await Seller.updateOne(
{
_id: seller_id,
"reviews.by": { $nin: [req.user.id] },
//knowing req.user._id is a mongoose.Types.ObjectId.
//You can also use [id1, id2, ...] to the array to check for other id's
},
{ $addToSet: { reviews: review } } //get the review that matches to the user_id
);
Here is the documentation for $nin operator: https://www.mongodb.com/docs/manual/reference/operator/query/nin/
You are pushing the review object inside an object.
Instead do this:
await Seller.updateOne(
{ _id: seller_id },
{ $addToSet: { reviews: review } }
);
I have a rooms model. Within it is an array of User's which has its own model.
Each user has a bunch of different attributes, some of them being boolean. Knowing the ID of the specific room and the specific user, I am attempting to change the boolean value within a specific User element within the sub array like this:
Room.findOne({_id: roomId, "users" : user}, { "$set" : { mutedAudio : false}})
.then(doc => {
console.log("Unmuted audio");
res.json(doc)
io.in(roomId).emit('userchange');
})
.catch(err => {
console.log(err);
})
(I'm using a user model instead of a user ID for seeking the user within the sub array. Could not get ID to work but can fetch object by comparing it to itself entirely.)
I get the error:
MongoError: Unsupported projection option: $set: { mutedAudio: true }
Anyone know the answer to this?
Thank you.
EDIT:
const RoomSchema = new Schema({
owner: {
id: {
type: String
},
username: {
type: String
}
},
roomname: {
type: String,
required: true
},
category: {
type: String,
required: true
},
password: {
type: String,
required: false
},
users: [UserSchema],
messages: [{
username: {
type: String
},
message: {
type: String
},
time: {
type: String
}
}],
date: {
type: Date,
default: Date.now
}
});
const UserSchema = new Schema({
id: {
type: String
},
username: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
avatar: {
type: String
},
date: {
type: Date,
default: Date.now
},
micEnabled: {
type: Boolean,
default: false
},
mutedAudio: {
type: Boolean,
default: true
}
});
Model.findOne() takes 4 parameters, the second being "optional fields to return", that's why you're getting the error, mongoose is trying to select fields to return according to $set: { mutedAudio: true } which is being passed as a second parameter (therefore considered to be a projection option).
Use Model.findOneAndUpdate() which takes an update object as a second parameter, along with the positional operator $.
Room.findOneAndUpdate(
{ "_id": roomId, "users._id": userID },{ "$set": { "users.$.mutedAudio": false } } )
.then(doc => {
console.log("Unmuted audio");
res.json(doc)
io.in(roomId).emit('userchange');
})
.catch(err => {
console.log(err);
})
Original answer by #Neil Lunn in Mongoose find/update subdocument
This question already has answers here:
Mongoose delete array element in document and save
(8 answers)
MongoDB, remove object from array
(7 answers)
Closed 5 years ago.
A user has the ability to add languages. languages are stored as an array of type teach or learn in the userschema. I can simply add a language to the languages.teach[] by using push, but how do i remove one?
language object example
let language = {
"code": FR
"level": 1
};
UserScema.js
var UserSchema = new Schema({
email: {
value: {
type: String,
lowercase: true,
//unique: true,
},
token: String,
verified: Boolean,
},
password: {
type: String,
},
phone: {
countryCode: {
type: String,
//required:true,
unique: true,
},
number: {
type: String,
required: true
},
code: String,
verified: {
type: Boolean,
default: false
},
},
jwt: String,
profile: {
username: String,
firstname: String,
lastname: String,
dob: String,
level: Number,
location: String,
image: String,
introduction: String,
},
languages: {
teach: [],
learn: [],
}
},
{
timestamps: {createdAt: 'created_at', updatedAt: 'updated_at'}
});
LanguagesController.js
destroy(req, res) {
let id = req.params.id;
let language = {
"code": req.body.code,
"level": req.body.level
};
let type = req.params.type;
User.findOne({'_id': id}, function (err, user) {
if (err) {
return res.status(404).json({
success: true,
status: 404,
data: err,
message: "User does not exist",
});
}
if (type === "teach") {
for (let i = 0; i < user.languages.teach.length; i++)
if (user.languages.teach[i].code === language.code) {
user.languages.teach[i].remove();
break;
}
}
if (type === "learn") {
//user.languages.learn.push(language);
}
console.log(user);
user.save((err, user) => {
return res.status(200).json({
success: true,
status: 201,
data: user,
message: "Successfully Deleted Language",
});
});
});
}
I tried to use .remove but im getting a user.languages.teach[i].remove is not a function.
Yes .remove is nothing on the array. You can use .filter to remove unwanted array elements.
It would be used like:
if (type === "teach") {
user.languages.teach = user.languages.teach.filter( o => o.code !== language.code)
}
This will remove all the element from the array with the condition given above.
Read more about Array.prototype.filter.
Maybe something like...
...
if (type === "teach") {
var index = user.lanauges.teach.findIndex(function(item){
return item.code === languge.code;
});
user.languages.teach.splice(index, 1);
....
I got it to work on accident with out adding a res.json(doc) but I found that when I make a POST request I need to send a response and ever since I added that response I get 0 or null?
add: function(req, res) {
//var newPlayer = new models.Team({ _id: req.params.tid }, { players: req.body });
models.Team.update({ _id: req.params.tid }, { $addToSet: { players: req.body} }, function(err, newPlayer){
if (err) {
res.json({error: 'Error.'});
} else {
res.json(newPlayer);
}
});
},
Also tried with findOneAndUpdate but my POST request is showing 0 or null for the response.
I am updating an array of objects inside a collection, it's nested. Here is the SCHEMA just to be clear.
var Team = new Schema({
team_name: { type: String },
players: [
{
player_name: { type: String },
points: { type: Number },
made_one: { type: Number },
made_two: { type: Number },
made_three: { type: Number },
missed_one: { type: Number },
missed_two: { type: Number },
missed_three: { type: Number },
percentage: { type: Number },
assists: { type: Number },
rebounds: { type: Number },
steals: { type: Number },
blocks: { type: Number },
fouls: { type: Number },
feed: { type: String },
facebook_id: { type: Number }
}
]
});
So my question is does anyone have any idea why I am getting that response 0?
The update method does not return the document in the response. The callback arguments are (err, numAffected) where numAffected is the number of documents touched by the "update" statement, which can possibly do "bulk" ( or multi ) processing.
What you want is findByIdAndUpdate() or findOneAndUpdate(). These methods return the either the original document or the modified document, according to the arguments you give.
add: function(req, res) {
models.Team.findByIdAndUpdate(
req.params.tid,
{ $addToSet: { players: req.body } },
function(err, newPlayer){
if (err) {
res.json({error: 'Error.'});
} else {
res.json(newPlayer);
}
}
);
},