I am facing a strange problem in trying to use $in operator with mongoose and node. Following is the snippet from the code.
queryObj = {imei: {$in: queryItems.imei}}
console.log(JSON.stringify(queryObj))
//{"imei":{"$in":[866551038558099,866551038558099, 866551038549072, 866551038536939, 866551038557844]}}
The query returns an empty array, whereas if I copy-paste the log in MongoDB Compass, I can see the result set.
const mongoose = require('mongoose');
const GeofenceReportSchema = new mongoose.Schema({
createdOn: {
type: Date,
default: new Date(),
required: true
},
targetDate: {
type: Date,
required: true
},
vehicleNo: {
type: String,
default: '',
required: true
},
imei: {
type: Number,
required: true
},
numberPlate: {
type: String,
default: '',
required: false
},
driverName: {
type: String,
default: '',
required: false
},
driverContact: {
type: Number,
default: 0,
required: false
},
startTimeIgnOn: {
type: String,
default: '',
required: false
},
endTimeIgnOff: {
type: String,
default: '',
required: false
},
idlingTime: {
type: Number,
default: 0,
required: false
},
distance: {
type: Number,
default: 0,
required: true
},
averageSpeed: {
type: Number,
default: 0,
required: true
},
engineHours: {
type: Number,
default: 0,
required: true
},
startOdometer: {
type: Number,
default: 0,
required: true
},
endOdometer: {
type: Number,
default: 0,
required: true
},
totalFuelConsumption: {
type: Number,
default: 0,
required: true
},
totalStops: {
type: Number,
default: 0,
required: true
},
geofenceInTime: {
type: Number,
default: 0,
required: false
},
geofenceOutTime: {
type: Number,
default: 0,
required: false
},
distanceInsideGeofence: {
type: Number,
default: 0,
required: false
},
distanceOutsideGeofence: {
type: Number,
default: 0,
required: false
},
performance: {
type: Number,
default: 0,
required: false
}
});
let model;
try {
model = mongoose.model('GeofenceReport');
} catch (error) {
model = mongoose.model('GeofenceReport', GeofenceReportSchema);
}
module.exports = model;
function getGeofenceReport(queryItems){
let queryObj = {$and: [ {targetDate: { $gte: new Date(queryItems.fromTime), $lte: new Date(queryItems.toTime)}},{imei: {$in: queryItems.imei}}]}
console.log(JSON.stringify(queryObj))
return new Promise((resolve, reject) => {
connectToDatabase().then(() => {
GeofenceReportSchema.find(queryObj)
.sort({"targetDate" : 1})
.then((resp) => {
resolve(resp);
})
.catch((err) => {
reject(err);
})
}).catch((err) => {
reject(err);
});
});
}
Sample data
{
"_id": {
"$oid": "606d82c585ac11242012cb37"
},
"createdOn": {
"$date": "2021-04-07T10:00:37.269Z"
},
"targetDate": {
"$date": "2021-04-06T14:30:00.000Z"
},
"vehicleNo": "ABCDE",
"imei": {
"$numberLong": "866551038558000"
},
"numberPlate": "",
"driverName": "John Doe",
"driverContact": 99999999,
"startTimeIgnOn": "2021-04-06T01:59:44.000Z",
"endTimeIgnOff": "2021-04-06T11:15:31.000Z",
"idlingTime": 8344000,
"distance": 27277.310000000056,
"averageSpeed": 3.59232320529802,
"engineHours": 23325000,
"startOdometer": 658548.82,
"endOdometer": 685826.13,
"totalFuelConsumption": 27.277310000000057,
"totalStops": 8,
"geofenceInTime": 18043000,
"geofenceOutTime": 5282000,
"distanceInsideGeofence": 4421.061251513145,
"distanceOutsideGeofence": 22856.248748486913,
"performance": 59.52
}
Invocation
{
fromTime : '2021-03-03T18:30:00.000Z',
toTime: '2021-03-31T18:29:59.000Z',
imei: 866551038558000
}
Note that I have already checked DB connections, have tried with the empty find method and I am able to get data. I have also checked data types. Isn't an issue there. What can be the issue?
Related
I'm trying to insert data from Google Reply to Reviews API into MongoDb using mongoose but some of the objects inserted have empty fields and some of them are nested key-value objects inside an Array which I don't know how to catch.
This is the JSON response from the API:
{
"reviews": [
{
"reviewId": "19940672-2a0f-470b-8760-05ce91add518",
"authorName": "el piculin 357",
"comments": [
{
"userComment": {
"text": "\tEs bueno y los logos son faciles de adivinar",
"lastModified": {
"seconds": "1675041753",
"nanos": 386000000
},
"starRating": 5,
"reviewerLanguage": "es",
"device": "grandpplte",
"androidOsVersion": 23,
"appVersionCode": 99,
"appVersionName": "2.5.0",
"deviceMetadata": {
"productName": "grandpplte (Galaxy J2 Prime)",
"manufacturer": "Samsung",
"deviceClass": "FORM_FACTOR_PHONE",
"screenWidthPx": 540,
"screenHeightPx": 960,
"nativePlatform": "ABI_ARM_V7,ABI_ARM",
"screenDensityDpi": 240,
"glEsVersion": 196609,
"ramMb": 1407
}
}
}
]
}
]
}
This is my Schema (review.model.js):
const mongoose = require("mongoose");
const ReviewSchema = new mongoose.Schema({
reviewId: { type: String, default: '', unique: true },
authorName: { type: String, default: '' },
userComment: {
text: { type: String, default: '' },
lastModified: {
seconds: { type: String, default: '' },
nanos: { type: Number, default: 0 },
},
starRating: { type: Number, default: 0 },
reviewerLanguage: { type: String, default: '' },
device: { type: String, default: '' },
androidOsVersion: { type: Number, default: 0 },
appVersionCode: { type: Number, default: 0 },
appVersionNumber: { type: String, default: '' },
thumbsUpCount: { type: Number, default: 0 },
thumbsDownCount: { type: Number, default: 0 },
},
developerComment: {
text: { type: String, default: '' },
lastModified: {
seconds: { type: String, default: '' },
nanos: { type: Number, default: 0 },
}
},
appInformation: {
packageIdentifier: { type: String, default: '' }
}
});
const Review = mongoose.model("Review", ReviewSchema);
module.exports = Review;
Another thing that I tried:
const mongoose = require("mongoose");
const AppInformationSchema = new mongoose.Schema({
packageIdentifier: { type: String, default: '' }
});
const DeveloperCommentSchema = new mongoose.Schema({
text: { type: String, default: '' },
lastModified: { LastModifiedSchema }
});
const LastModifiedSchema = new mongoose.Schema({
seconds: { type: String, default: '' },
nanos: { type: Number, default: 0 },
});
const UserCommentScehma = new mongoose.Schema({
text: { type: String, default: '' },
lastModified: { type: LastModifiedSchema },
starRating: { type: Number, default: 0 },
reviewerLanguage: { type: String, default: '' },
device: { type: String, default: '' },
androidOsVersion: { type: Number, default: 0 },
appVersionCode: { type: Number, default: 0 },
appVersionNumber: { type: String, default: '' },
thumbsUpCount: { type: Number, default: 0 },
thumbsDownCount: { type: Number, default: 0 }
});
const ReviewSchema = new mongoose.Schema({
reviewId: { type: String, default: '', unique: true },
authorName: { type: String, default: '' },
comments: [UserCommentScehma, DeveloperCommentSchema],
appInformation: { AppInformationSchema }
});
const Review = mongoose.model("Review", ReviewSchema);
module.exports = Review;
But I get an error when trying to implement it like that:
ReferenceError: Cannot access 'LastModifiedSchema' before initialization
What is the right way of implementing it?
As UserCommentScehma is under userComment itself, so you need to consider this structure in the schema as well.
const ReviewSchema = new mongoose.Schema({
reviewId: { type: String, default: '', unique: true },
authorName: { type: String, default: '' },
comments: [{ userComment: UserCommentScehma }, DeveloperCommentSchema],
appInformation: { AppInformationSchema }
});
So I created this controller to get me the sum of all the orders totalPrice made by months
const getMonthlyOrderTotal = async (req, res) => {
try {
const year = req.params.year;
const aggregatePipeline = [
{
$match: {
createdAt: {
$gte: new Date(`${year}-01-01T00:00:00.000`),
$lt: new Date(`${year}-12-31T23:59:59.999`)
}
}
},
{
$group: {
_id: {
$month: "$createdAt"
},
total: {
$sum: "$totalPrice"
}
}
},
{
$sort: {
_id: 1
}
}
];
const orderTotals = await Order.aggregate(aggregatePipeline);
res.json(orderTotals);
} catch (err) {
res.status(500).json({ message: err.message });
}
};
this is the orderModel I am using
import mongoose from "mongoose";
const orderSchema = mongoose.Schema(
{
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "User",
},
client: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "Client",
},
orderItems: [
{
name: { type: String, required: true },
qty: { type: Number, required: true },
image: { type: String },
price: { type: Number, required: true },
product: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "Product",
},
},
],
totalPrice: {
type: Number,
required: true,
default: 0.0,
},
taxPrice: {
type: Number,
required: true,
default: 0.0,
},
isPaid: {
type: Boolean,
required: true,
default: false,
},
paidAt: {
type: Date,
},
isDelivered: {
type: Boolean,
required: true,
default: false,
},
deliveredAt: {
type: Date,
},
},
{
timestamps: true,
}
);
const Order = mongoose.model("Order", orderSchema);
export default Order;
and when I try to test this API in postman "http://localhost:5001/orders/orderstotal/2022" I always get an empty array even though there is stored data in mongoDB orders Collection
I'm having an error on my database where the sub array that I push to my database is missing and created a new id which means it detects data pushed inside.
here's the data I pushed. (toDeliver array has 4 objects inside).
I'm trying to send the whole array along with the string outside of the array.
after the request here what I receive on my database which is mongoDB.
the object inside toDeliver array is incomplete and created a ObjectId.
but the string outside of array was save the database.
here's my schema.
const OwnerSchema = mongoose.Schema({
username: {
require: true,
type: String,
},
password: {
require: true,
type: String,
},
isAdmin: {
type: Boolean,
default: true,
},
store: [
{
product_identifier: {
type: String,
require: true,
},
productname: {
type: String,
required: true,
},
price: {
type: Number,
required: true,
},
quantity: {
type: Number,
required: true,
},
categoryfilter: {
type: String,
required: true
},
description: {
type: String,
required: true,
},
specs: {
type: String,
required: true
},
imageBase64: {
type: String,
required: true,
},
timestamp: {
type: String,
required: true,
}
}
],
delivery: [
{
clientname: {
type: String,
required: true
},
address: {
type: String,
required: true
},
email: {
type: String,
required: true
},
number: {
type: Number,
required: true
},
toDeliver: [
{
product_identifier: {
type: String,
require: true,
},
productname: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
}
],
toDeliverPaidViaPaypal: [
{
product_identifier: {
type: String,
require: true,
},
productname: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
}
]
}
]
});
here's my backend.
export const delivery = async (req,res) => {
const { id } = req.params;
console.log(id);
console.log(req.body);
try {
if(!id) return res.status(404).json({ message: 'ID not found' });
await OwnerModels.findByIdAndUpdate(id,
{
$push: {
delivery:
{
clientname: req.body.delivery[0].clientname,
address: req.body.delivery[0].address,
email: req.body.delivery[0].email,
number: req.body.delivery[0].number,
toDeliver:
[{
product_identifier: req.body.delivery[0].toDeliver.product_identifier,
productname: req.body.delivery[0].toDeliver.productname,
price: req.body.delivery[0].toDeliver.price
}]
,
toDeliverPaidViaPaypal: []
}
}
},
{
new: true,
},(err,res)=> {
if(err) return console.log({ error: err });
console.log({ result: res.delivery });
}).clone();
} catch (error) {
res.status(500).json({ message: 'Server error' });
}
}
hope ya guys can help me. thank you
I think you need to add square brackets around the toDeliver object to make it an array like your console object:
$push: {
delivery: {
clientname: req.body.delivery[0].clientname,
address: req.body.delivery[0].address,
email: req.body.delivery[0].email,
number: req.body.delivery[0].number,
toDeliver: [{
product_identifier: req.body.delivery[0].toDeliver.product_identifier,
productname: req.body.delivery[0].toDeliver.productname,
price: req.body.delivery[0].toDeliver.price
}],
toDeliverPaidViaPaypal: []
}
}
Also add "_id: false" to toDelivery in your schema to repress id from being generated for the sub-object:
toDeliver: [
{
product_identifier: {
type: String,
require: true,
},
productname: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
_id: false,
}
],
I have a schema of Delivery:
const DeliverySchema = new mongoose.Schema({
projectId: { type: String, default: "", trim: true },
tasks: [{
timestamp: { type: Date, default: new Date() },
isAssigned: { type: Boolean, default: false },
dr1Manager: { type: Schema.Types.ObjectId, ref: 'User' },
dr2Manager: { type: Schema.Types.ObjectId, ref: 'User' },
status: { type: String, default: "dr1", trim: true },
pair: { type: String, default: "", trim: true },
taskId: { type: String, default: "", trim: true },
files: [{
fileName: { type: String, default: "", trim: true },
path: { type: String, default: "", trim: true },
isFileApproved: { type: Boolean, default: false },
isOriginal: { type: Boolean, default: false },
}],
instructions: [{
step: { type: String, default: "dr1", trim: true },
text: { type: String, default: "", trim: true },
isChecked: { type: Boolean, default: false }
}],
}]
});
I'd like to know if I can $pull data from instructions array and change remaining elements in that array in the same query. I'm trying to do it this way:
await Delivery.updateOne(
{ projectId, "tasks.taskId": taskId },
{
"tasks.$[i].isAssigned": false,
"tasks.$[i].status": "dr1",
"tasks.$[i].dr1Manager": manager,
$pull: { "tasks.$[i].instructions": { step: "dr2" } },
"tasks.$[i].files.$[j].isFileApproved": false,
"tasks.$[i].instructions.$[k].isChecked": false
},
{
arrayFilters: [
{ "i.taskId": taskId },
{ "j.isFileApproved": true },
{ "k.isChecked": true }
]
}
);
As a result I get an error:
Updating the path \'tasks.$[i].instructions\' would create a conflict
at \'tasks.$[i].instructions\
So how can I get that done?
Don't know if that would be suitable, but you can use bulkWrite:
await Delivery.bulkWrite([
{
updateOne: {
filter: { projectId, "tasks.taskId": taskId },
update: {
"tasks.$[i].isAssigned": false,
"tasks.$[i].status": "dr1",
"tasks.$[i].dr1Manager": manager,
$pull: { "tasks.$[i].instructions": { step: "dr2" } },
"tasks.$[i].files.$[j].isFileApproved": false
},
arrayFilters: [{ "i.taskId": taskId }, { "j.isFileApproved": true }]
}
},
{
updateOne: {
filter: { projectId, "tasks.taskId": taskId },
update: {
"tasks.$[i].instructions.$[k].isChecked": false
},
arrayFilters: [{ "i.taskId": taskId }, { "k.isChecked": true }]
}
}
]);
Here is the docs
i have a scheme like this
var WFWorkItemDocument = new Schema({
id: { type: String, required: true, unique: true, default: uuid.v1 },
description: { type: String },
period: [{
id: { type: String, default: uuid.v1 },
start: { type: Date, default: Date.now }
due: { type: Number, integer: true },
new: { type: Number, integer: true },
}],
i want to get the period's due value for that i used a method like
WorkItem.findOne({ id: idUpdate }, function(err, WorkItem) {
if (err) {
console.log("invlaid id");
//return res.send(404, { error: 'invalid id' });
}
if (WorkItem) {
console.log("id");
console.log(WorkItem.period.due);
} else {
//res.send(404, new Error('Workitem not found'));
}
});
but it doesn't work how can i get the due value??
This is the result for console.log(WorkItem)
Change the schema to embed one object. Unless you need embedded array.
var WFWorkItemDocument = new Schema({
id: { type: String, required: true, unique: true, default: uuid.v1 },
description: { type: String },
period: {
id: { type: String, default: uuid.v1 },
start: { type: Date, default: Date.now }
due: { type: Number, integer: true },
new: { type: Number, integer: true },
},
And if you define it as an embedded array, you can access like :
WorkItem.period[index].due