Query mongoose model using variable as key in nested document - mongodb

I am having some trouble using model.find to return a list of documents that match a variable condition within my nested schema. I am using node, express, and mongoose for this project.
Ideally I want to use a variable as the object key within the query so I can dynamically grab the day of the week and check the open hours. I haven't had any success so far in finding an answer for this online.
Here is my model.
const restaurantSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: { type: String, required: true },
coordinates: {
latitude: { type: Number, required: true },
longitude: { type: Number, required: true }
},
happy_hour: {
sunday: {
open: { type: Boolean },
open_at: { type: Number },
close_at: { type: Number }
},
monday: {
open: { type: Boolean },
open_at: { type: Number },
close_at: { type: Number }
},
tuesday: {
open: { type: Boolean },
open_at: { type: Number },
close_at: { type: Number }
},
wednesday: {
open: { type: Boolean },
open_at: { type: Number },
close_at: { type: Number }
},
thursday: {
open: { type: Boolean },
open_at: { type: Number },
close_at: { type: Number }
},
friday: {
open: { type: Boolean },
open_at: { type: Number },
close_at: { type: Number }
},
saturday: {
open: { type: Boolean },
open_at: { type: Number },
close_at: { type: Number }
}
}
});
Here is a snippet from the controller that is handling the logic for this express route. The snippet below has a static key called "Friday", but I want to dynamically get the day of the week and pass that in as a variable, something like $friday: { open: true } or what not.
exports.search = (req, res, next) => {
const radius = req.query.radius || 5;
const latitude = req.query.latitude;
const longitude = req.query.longitude;
const day = date.get_day();
const minutes = date.get_minutes();
console.log(query[day]);
if ( latitude == undefined || longitude == undefined ) {
res.status(404).json({
message: "Missing longitude or latitude"
})
}
Restaurant.find({
hours: {
friday: {
open: true
}
}
})
.exec()
.then(results => {
res.status(200).json({
data: results.map( result => {

You can try this
var day = req.params.dayName;
var query = {};
query["hours"] = {[day] :true};
collection.find(query, function (err, item) { ... });

You have multiple options to do that.
The query that mongoose expects, is just an object.
const query = { hours : {} };
hours[getTheCurrentDay()].open = true;
// Or with es6
const query = { hours : { [getTheCurrentDay()] : { open : true } };
// Or with pure string
const query = { `hours.${getTheCurrentDay()}.open` : true };
Restaurant.find( query ).exec()...

Related

Change field in object in array of object

I have a field achivment with an array of objects. I need to update the field currentPoints in one object that I will find by field name in the array.
Code model of mongoose:
const achive = new Schema(
{
achiveId: ObjectId,
name: { type: String, required: true },
finishedPoints: { type: Number, required: true },
currentPoints: {
type: Number,
default: 0,
set: function (v) {
if (v >= this.finishedPoints) this.isFinished = true;
return v;
}
},
isFinished: { type: Boolean, default: false }
},
{ _id: false }
);
const achivesSchema = new Schema({
userId: ObjectId,
achivement: [achive]
});
Code query:
export async function progressAchive(req, res) {
const value = 3;
try {
const test = await Achives.updateOne(
{
userId: req.user._id,
achivement: { $elemMatch: { name: req.params.nameAchive } }
},
{ $set: { achivement: { currentPoints: value } } },
{ new: true }
);
res.json(test);
} catch (e) {
console.log(e);
}
}
Instead of updating, it removes all objects from the array and leaves them one object with the currentPoint field. How can I update this like I want?
You should use the following for update
const test = await Achives.updateOne(
{
userId: req.user._id,
},
{
$set:{"achivement.$[el].currentPoints": value}
},
{
arrayFilters:[{
"el.name": req.params.nameAchive
}],
new: true
}
);

How to automatically delete documents when boolean is false and time is up in mongodb

so I have this schema:
{
email: {
type: String,
},
username: { type: String },
createdAt: {
type: Date,
default: Date.now,
},
points: {
type: Number,
default: 0,
},
location: {
type: String,
},
validation: {
type: String,
},
isValidated: {
type: Boolean,
default: false,
},
roles: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Role",
},
],
password: {
type: String,
},
},
{ collection: "users" }
)
Now that I'm trying to id is to delete this document automatically after 2 minutes if this parameter isValidated is set to false. I know if I set expire_at it will delete document, but don't know how to do this?
I would just set expire_at to 2 minutes in the future in the same place you set isValidated to false.
//Pseudocode because I'm not sure the exact syntax for this
let invalidate = (document) => {
document.isValidated = false
date = new Date()
date += 2 minutes
document.expire_at = date
document.save()
}

How to update any amount of fields in a nested documen in Mongoose?

I need to update different fields of a nested array in Mongoose. Sometimes I will send runId and runStatus, some other times siteFetched and some other times siteInfo.
I have tried with the following code but the $set operator replaces the old fields.
The model:
campaignId: { type: String },
keywords: [{
keyword: { type: String },
serp: {
runId: { type: String },
runStatus: { type: String },
siteFetched: { type: Boolean },
sitesInfo: [{
title: { type: String },
url: { type: String },
description: { type: String },
}],
},
},
],
Here is the code to update
const campaign = await Campaign.findOneAndUpdate(
{ _id: campaignId, "keywords.keyword": keyword },
{
$set: { "keywords.$.apifySerp": {...serp }},
}
);
the value for serp varies like
const serp = {
runId: '1kLgbnvpADsDJyP1x',
runStatus: 'READY'
}
and
const serp = {
siteFetched: true
}
Here is the code that solved my problem.
const serp = {
siteFetched: true,
};
let update = Object.keys(serp).reduce((acc, cur) => {
acc[`keywords.$.apifySerp.${cur}`] = serp[cur];
return acc;
}, {});

Meteor collection2 does not validate on the client side

I am using collection2 with meteor to set default values. However when i run the method Meteor.call('commands.insert', {}) on the client, it just sets new document's ID, and only when the result from server comes it replaces the document with the right value. Actually, autoValue function runs on client because when i console.log there it logs (also tried defaultValue), but it does not do anything, does no modifications, nor unique: true is working, any property specified in the schema
server
export const Commands = new Mongo.Collection('commands')
Commands.schema = new SimpleSchema({
designation: {
type: String,
autoValue: function() {
console.log("inssssssssssssssssssseeeeeeeeeeeeeeeeeeeeeeert")
if (this.isInsert) {
return "Untitled"
}
},
unique: true
},
name: {
type: String,
autoValue: function() {
if (this.isInsert) {
return ""
}
},
optional: true
},
syntax: {
type: String,
autoValue: function() {
if (this.isInsert) {
return ""
}
},
optional: true
},
description: {
type: String,
autoValue: function() {
if (this.isInsert) {
return ""
}
},
optional: true
},
features: {
type: String,
autoValue: function() {
if (this.isInsert) {
return ""
}
},
optional: true},
type: {
type: String,
autoValue: function() {
if (this.isInsert) {
return ""
}
},
optional: true
},
variants: {
type: Array,
autoValue: function() {
if (this.isInsert) {
return []
}
},
},
'variants.$': {type: String}
})
Commands.attachSchema(Commands.schema)
Meteor.methods({
'commands.insert'(command) {
if (!this.userId) {
throw new Meteor.Error('not-authorized')
}
Commands.insert(command)
}
})
client
const setNewHandler = this.props.page.animationFinished ?
this.props.page.editing ?
textEditorData.length ?
() => {
Meteor.call(
'commands.update',
textEditorData[0]._id,
{
designation:
this.childComponents[0].editableContentNode.textContent,
name:
this.childComponents[1].editableContentNode.textContent,
syntax:
this.childComponents[2].editableContentNode.textContent,
type:
this.childComponents[3].editableContentNode.textContent,
variants:
this.childComponents[4].editableContentNode.textContent.split("\n"),
description:
this.childComponents[5].editableContentNode.textContent,
features:
this.childComponents[6].editableContentNode.textContent
}
)
} :
null :
() => {
Meteor.call('commands.insert', {})
} :
null

How can I overwrite the entire document, instead of just updating the fields?

How can I overwrite the entire document, instead of just updating the fields?
Here is the method I use right now but doesn't work:
updateFilmTitle: function(req, res) {
var id = req.params.id;
console.log(id);
filmTitleModel.findByIdAndUpdate(id, req.body, {
overwrite: true
}, {
new: true
}, (error, response) => {
if (error) {
res.json(error);
console.error(error);
return;
}
console.log("filmTitle form has been updated!");
res.json(response);
console.log(response);
});
},
here how my model looks like,
var venueSchema = new Schema({
ticketServiceRequired: { type: Boolean, required: true },
filmSettings: {
type: {
filmContactName: { type: String, required: true },
filmSeatingAmount: { type: Number, required: true },
filmMediaDelivery: { type: Array, required: true },
filmRentalFee: {
price: { type: Number, required: true },
type: { type: String, required: true },
},
}
},
});
new and overwrite both are options, so it should be this:
filmTitleModel.findByIdAndUpdate(id, req.body, {
overwrite : true,
new : true
}, (error, response) => { ... });