I have schema for products and it has a field storeZones object in it defined as
...
storeZones: {
type: {
masterZone: {type: Schema.Types.ObjectId, model: 'Zone', index: 1 },
zone: { type: Schema.Types.ObjectId, model: 'Zone', index: 1 },
subZone: { type: Schema.Types.ObjectId, model: 'Zone', index: 1 },
},
default: {
masterZone: null,
zone: null,
subZone: null,
},
},
...
I am counting for products in a specific masterZone. So my query is
const condition = { 'storeZones.masterZone': masterZone };
console.log(condition); // { 'storeZones.masterZone': '60533e6a745d465ab6cb3fc9' }
const total = await Product.count(condition);
This returns 0 results.
But when i paste the exact query in mongo shell; Robo3t to be exact.
db.products.find({'storeZones.masterZone': ObjectId('60533e6a745d465ab6cb3fc9') } )
It produces the desired output. Can someone please provide some assistance?
Fixed it by converting the masterZone from request to an ObjectId. Idk why i needed to do this, but that fixed it! so...
const m = mongoose.Types.ObjectId(masterZone);
const condition = { 'storeZones.masterZone': m };
console.log(condition); // { 'storeZones.masterZone': '60533e6a745d465ab6cb3fc9'}
const total = await Product.count(condition);
Related
I have a controller where I am trying to query the most popular posts within the last week, sorted by most popular, and has a max cap of 50 posts. I am trying to use the aggregate() method; however, I am not sure if I am doing it correctly. When I run the query In insomnia I get an error like so:
{
"ok": 0,
"code": 8000,
"codeName": "AtlasError"
}
Here is my post model:
const postSchema = mongoose.Schema({
title: {
type: String,
required: true
},
message: {
type: String,
required: true
},
//replace creator with name
name: String,
creator: String,
tags: [String],
size: String,
selectedFile: String,
likes: {
type: [String],
default: [],
},
comments: {
type: [String],
default: []
},
createdAt: {
type: Date,
default: new Date(),
},
dogTreats: {
type: Number,
default: 0,
required: false,
}
});
and here is my controller/post.js
export const getPopular = async (req, res) => {
//get current time
let currentTime = new Date()
//get from 7 days ago
currentTime.setDate(currentTime.getDate()-7)
console.log(currentTime) // -> output 2022-09-04T19:29:39.612Z
try {
//sort posts by most likes and within 7 days ago, but with a max of 50 posts
const mostPopular = await PostMessage.aggregate([{"$sort": { likes: -1}}, { "$limit": 50}, { "$gt": currentTime }])
res.status(200).json(mostPopular)
} catch (error) {
res.status(500).json(error)
}
}
You can use find method. It is better to use here.
If you need to reach a value from another table populated, aggregation is better to use. However, at here, find is the best way to reach datas.
const mostPopular = await PostMessage.find({createdAt: {$gt : currentTime}}).sort({likes: -1}).limit(50)
Try this aggregation
export const getPopular = async (req, res) => {
//get current time
let currentTime = new Date()
//get from 7 days ago
currentTime.setDate(currentTime.getDate() - 7)
console.log(currentTime) // -> output 2022-09-04T19:29:39.612Z
try {
//sort posts by most likes and within 7 days ago, but with a max of 50 posts
const mostPopular = await PostMessage.aggregate([
{ $match: { createdAt: { $gt: currentTime } } },
{ $sort: { likes: -1 } },
{ $limit: 50 }
])
res.status(200).json(mostPopular)
} catch (error) {
res.status(500).json(error)
}
}
I built an ordering system with Node JS and MongoDB, I want to calculate order total_price in server before save it as a new order,
let ref = (model) => {
return { type: mongoose.Schema.Types.ObjectId, required: true, ref: model };
};
this is my order model schema
{
items: [
{
id: ref("menu_item"),
count: String,
size: String,
options: [String],
},
],
total_price: String,
tip: String,
};
and this is menu_item model schema
{
name: String,
price: String,
vat: String, // 3%
size: [
{
name: String,
unit: String,
price: String,
vat: String, // 3%
in_stock: Boolean,
is_default: Boolean,
},
],
options: [
{
title: String,
options: [
{
name: String,
price: String,
vat: String, // 3%
in_stock: Boolean,
is_default: Boolean,
},
],
},
],
}
How it's possible?
this is some tried that I done but it's wrong way.
when customer send an order this function will be call
async (req, res) => {
let total = 0;
let size_price = 0;
let options_price = 0;
let {
items,
tip,
} = req.body;
let price = 0;
let item_price = items.forEach(async (el) => {
let menu_item = await req.models.menu_item.findOne({ _id: el.id });
price += parseInt(menu_item.price);
console.log(menu_item.price) // first 12 second 9
console.log(price) // first 12 second 21
});
console.log(price) // return 0
}
forEach loop does not wait for async functions to complete before executing next iteration / exiting the loop. In order to wait till all records are queried from DB and price value is updated, we can either wrap all promises in Promise.all or execute them serially in for-of loop.
Here is the updated code using Promise.all:
async (req, res) => {
let total = 0;
let size_price = 0;
let options_price = 0;
let {
items,
tip,
} = req.body;
let price = 0;
await Promise.all(items.map(async (el) => {
let menu_item = await req.models.menu_item.findOne({ _id: el.id });
price += parseInt(menu_item.price);
console.log(menu_item.price) // first 12 second 9
console.log(price) // first 12 second 21
})
);
console.log(price) // return 0
}
Hi everyone I have an array of objects with some populated fields. This is the schema of the product.
import mongoose, { Schema } from 'mongoose';
const productSchema = new mongoose.Schema(
{
name: String,
description: String,
sku: String,
barcode: String,
isActive: Boolean,
quantity: Number,
availability: String,
taxClass: [{ type: Schema.Types.ObjectId, ref: 'TaxClass' }],
images: [{ type: Schema.Types.ObjectId, ref: 'Image' }],
variants: [{ type: Schema.Types.ObjectId, ref: 'Variant' }],
tags: [{ type: Schema.Types.ObjectId, ref: 'Tag' }],
price: {
comparePrice: Number,
price: Number
},
seo: {
name: String,
keywords: [
{
name: String
}
],
description: String,
image: String
}
},
{ timestamps: true }
);
const Product = mongoose.model('Product', productSchema);
export default Product;
So i have a function and I want to return all the products with the variant color of green.
export const returnFilteredProducts = async (_, { filters = null, page = 1, limit = 20 }, context) => {
await jwtAuthentication.verifyTokenMiddleware(context);
try {
let searchQuery = {};
const products = await Product.find(searchQuery).populate(['variants', 'tags', 'images', 'taxClass']);
console.log(products.filter((item) => item.variants.filter((e) => e.color.indexOf('green') >= 0)));
return {
products
};
} catch (error) {
handleError(error);
}
};
The thing is that it does not return me the document with a variant color of green, instead it returns all the documents.
I am implementing a filtering system so I don't filter the products with in the frontend with redux.
Regarding the filtering method that is applied into the products array:
products.filter((item) => item.variants.filter((e) => e.color.indexOf('green') >= 0))
Inner call item.variants.filter() returns an array.
The outer call: products.filter() will include the product item, since the array will coerce into true, even when empty.
You can use method Array.some() for the inner call,
which will return a boolean true if at least one item (e) in item.variants
has the desired color.
This way you will filter-out all the product items that do-not contain the desired color in at least one element of the item.variants array.
I'm trying to update a document in a mongo database with information from a form, with all the form going into a field which is an array. At the moment I can't get it to update a document, only create a new one, but more pressingly I can't get the information from the form into the array.
Here is my schema:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const WorkoutSchema = new Schema({
day: {
type: Date,
default: Date.now
},
exercises: [
{
type: String,
trim: true,
required: "Exercise type is required"
},
{
name: String,
trim: true,
required: "Exercise name is required"
},
{
duration: Number
},
{
weight: Number
},
{
reps: Number
},
{
sets: Number
},
{
duration: Number
},
{
distance: Number
}
]
});
const Workout = mongoose.model("Workout", WorkoutSchema);
module.exports = Workout;
And here is my API route. I've included the results of console.logs below it so you can see the information that is getting passed.
app.put("/api/workouts/:id", (req, res) => {
console.log("api body: " + JSON.stringify(req.body));
console.log("body is " + typeof req.body);
var body = JSON.stringify(req.body);
// body = body.split("{")[1];
// body = body.split("}")[0];
// body = "["+body+"]";
console.log(body);
Workout.create({exercises: `${body}`})
.then(Workout => {
res.json(Workout);
})
.catch(err => {
res.json(err);
});
});
api body: {"type":"resistance","name":"Test Press","weight":100,"sets":5,"reps":6,"duration":10}
body is object
{"type":"resistance","name":"Test Press","weight":100,"sets":5,"reps":6,"duration":10}
In the database I get exercises as an array with one element - the above object - instead of a series of key/value pairs. I've tried a lot of things, but this is as close as I get to what I'm trying to do.
Can anyone see where I've gone wrong?
This turned out to be a basic syntax error which came about because one of my keys was "type". The issue is in the syntax of the exercises array, the model should look like this:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const WorkoutSchema = new Schema({
day: {
type: Date,
default: Date.now
},
exercises: [{
type: {
type: String,
trim: true,
required: "Exercise type is required"
},
name: {
type: String,
trim: true,
required: "Exercise name is required"
},
duration: {
type: Number,
required: "Duration is required"
},
weight: {
type: Number
},
reps: {
type: Number
},
sets: {
type: Number
},
distance: {
type: Number
}
}]
});
const Workout = mongoose.model("Workout", WorkoutSchema);
module.exports = Workout;
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(...);
})