Mongoose $gte and $lte queries not working - node.js

I have the following method:
const getArbolMarkers = async ({ latitudes, longitudes }) => {
// console.log(latitudes, longitudes);
try {
const markersLatLon = await Arbol.find({}, {
_id: 0,
lon: true,
})
for (let i = 0; i < markersLatLon.length; i++) {
if (markersLatLon[i].lon >= longitudes.min && markersLatLon[i].lon <= longitudes.max) console.log('DBLon: ' + markersLatLon[i].lon + '\nMaxLon: ' + longitudes.max + '\nMinLon: ' + longitudes.min + '\n');
}
const markers = await Arbol.find({
lon: {
$gte: longitudes.min,
$lte: longitudes.max
}
})
return markers;
} catch (err) {
console.log(err);
return res.status(500).send("Error");
}
};
And this is my model:
var mongoose = require('mongoose');
const ArbolSchema = mongoose.Schema({
name: {
type: String,
require: true
},
lat: {
type: Number,
require: true
},
lon: {
type: Number,
require: true
},
});
module.exports = mongoose.model('ArbolSchema', ArbolSchema, 'arboles');
When I try to filter my collection through $gte and $lte, i'm not receiving any value, just an empty array. But when doing it "manually" in my for cycle i'm obtaining the following input:
DBLon: -106.07637092471123
MaxLon: -106.07548742070055
MinLon: -106.07696542070055
DBLon: -106.07608459889889
MaxLon: -106.07548742070055
MinLon: -106.07696542070055
DBLon: -106.0762995108962
MaxLon: -106.07548742070055
MinLon: -106.07696542070055
...
Meaning that there are multiple records that really exists on my collection and meet the conditions for max and min lon. Is there any reason in particular for this behaviour?

Related

How to stub query helper method Mongoose?

I'm using Sinon to test my Express/Typescript application. In Mongoose I have models with query helper methods to make query chains.
I have this schema
export const articuloSchema = new Schema({
_id: { type: String, default: v4 },
numeroInventario: { type: String, required: true, unique: true },
descripcion: { type: String, trim: true },
}, {
versionKey: false,
query: {
paginate(page: number, limit: number) {
return this.skip(page - 1).limit(limit);
}
}
});
export type ArticuloType = InferSchemaType<typeof articuloSchema>;
export const Articulo = mongoose.model('Articulo', articuloSchema);
and I want to fake my query helper method with Sinon like this
const getMultipleArticulos (): ArticuloType[] => {
const arr:ArticuloType = []
for (let i = 0; i < 5; i++) {
arr.push({
numeroInventario: i,
descripcion: 'string'
})
}
return arr;
}
it('Should return a list of items that belong to a user', function (done) {
const paginateFake = sinon.fake.resolves(getMultipleArticulos());
sinon.replace(Articulo, 'paginate', paginateFake);
chai.request(app)
.get(`/api/v1/users/${userId}/articulos`)
.end((err, res) => {
expect(err).to.be.null;
expect(res).to.have.status(200);
// more expects
done();
});
});
The problem is that I cannot stub those methods, it says that it can't stub non existent property of 'paginate' (which is the query helper method I added to my model).

MongoDB UpdateMany Method

how can i use the update Many Method inside my code?. Right now this code will insert the data over and over inside the table, i need to make it so it will update the old data and add new data if new data is available in the third party api. I'm new to MongoDB any help will be much appreciate it! thanks.
cron.schedule('0 0 * * *', async () => {
const postSchema = new mongoose.Schema({
id: {
type: Number,
required: true
},
name: {
type: String,
required: true
},
status: {
type: String,
required: false
},
});
const Post = mongoose.model('players', postSchema);
async function getPosts() {
const getPlayers = await fetch("http://localhost:3008/api/players");
const response = await getPlayers.json();
for( let i = 0;i < response.players.length; i++){
const post = new Post({
id: response.players[i]['id'],
name: response.players[i]['name'],
status: response.players[i]['status'],
});
post.save();
}
}
console.log("Task submitted successfully")
await getPosts();
});
what i was thinking
const post = await Post.updateMany({
id: response.players[i]['id'],
name: response.players[i]['name'],
status: response.players[i]['status'],
});
I believe you can use bulkWrite and inside bulkWrite you can write updateOne operation with the upsert flag set to true
You can construct an array of operations as follows
let operations = [];
for (let player of players) {
operations.push({
updateOne: {
filter: { id: player.id },
update: { $set: { name: player.name } },
upsert: true,
}
})
}
And finally you can make a call to bulkWrite. Please read the documentation for the operations above

How should I change the value of the field before saving it to database?

I am new to Node.js and I'm trying to perform CRUD operation right now. I have this function to save data to the mongoDB database but the thing is I'm trying to change the value of one particular field before saving it to database. The problem is that my data is getting saved first and then the calculations are being performed. Here is my post function:
router.post('/', async(req, res) => {
const reservation = new Reservation({
guestID: mongoose.Types.ObjectId(req.body.guestID),
roomID: mongoose.Types.ObjectId(req.body.roomID),
checkIn: req.body.checkIn,
checkOut: req.body.checkOut,
numberOfAdults: req.body.numberOfAdults,
totalCost: req.body.totalCost,
numberOfChildren: req.body.numberOfChildren
})
try
{
const reservationRecord = await reservation.save()
res.json(reservationRecord)
}
catch(err)
{
console.log(err)
res.send("Error")
}
})
And here is the Schema
const mongoose = require('mongoose')
const axios = require('axios')
const reservationSchema = new mongoose.Schema({
guestID: {
type: mongoose.SchemaTypes.ObjectId,
required: true
},
roomID: {
type: mongoose.SchemaTypes.ObjectId,
required: true
},
checkIn: {
type: Date,
required: true
},
checkOut: {
type: Date,
required: true
},
numberOfAdults: {
type: Number,
required: true
},
numberOfChildren: {
type: Number,
required: true
},
totalCost: {
type: Number,
required: false,
default: 0
}
})
reservationSchema.pre('save', function(next){
var date1 = new Date(this.checkIn);
var date2 = new Date(this.checkOut);
var diff = Math.abs(date1.getTime() - date2.getTime());
var diffDays = Math.ceil(diff / (1000 * 3600 * 24));
console.log(diffDays)
var roomCost
var totalRoomCost
axios.get("http://localhost:5555/rooms/" + this.roomID).then((response) => {
console.log(response)
roomCost = response.data.cost;
console.log("room cost is " + roomCost)
totalRoomCost = (this.numberOfAdults + this.numberOfChildren) * response.data.cost * diffDays
this.totalCost = totalRoomCost
})
//this.totalCost = (this.numberOfAdults + this.numberOfChildren) * roomCost * diffDays
console.log(this.totalCost)
next()
})
const Reservation = mongoose.model('reservation', reservationSchema)
module.exports = Reservation
I want to change the value of totalCost before saving it to database. Can somebody let me know what the problem is with the code?
Thank you!
You should just handle the calculations in your POST method, before your create your new Reservation instance:
router.post('/', async (req, res) => {
try {
const {
numberOfChildren,
numberOfAdults,
roomID,
checkIn,
checkOut,
} = req.body;
var date1 = new Date(checkIn);
var date2 = new Date(checkOut);
var diff = Math.abs(date1.getTime() - date2.getTime());
var diffDays = Math.ceil(diff / (1000 * 3600 * 24));
const room = await Room.findById(roomID)
const newTotalCost = (numberOfAdults + numberOfChildren) * room.cost * diffDays;
const reservation = new Reservation({
...req.body,
totalCost: newTotalCost,
});
const reservationRecord = await reservation.save();
res.json(reservationRecord);
} catch (err) {
console.log(err);
res.send('Error');
}
});
Of course, the reservationSchema.pre('save') function is unecessary in this case.

Mongoose set empty array when update model

I have a problem with mongoose. I use MEAN stack.
I have an House Schema with some fields. When I update the house (with save method) mongoose update all fields but set an array in nested object empty. Why?
HOUSE SCHEMA
const mongoose = require('mongoose');
const posSchema = require('./pos');
const reviewSchema = require('./reviews');
const roomSchema = require('./rooms');
const contactSchema = require('./contacts');
const nearSchema = require('./nears');
const houseSchema = new mongoose.Schema({
title: { type: String, required: true },
description: { type: String, required: true },
shared: {
description: { type: String, required: true },
photos: { type: [String], required: true }
},
// OTHER FIELDS
}, { timestamps: true });
mongoose.model('House', houseSchema);
UPDATE FUNCTION
House.findById(body.house._id, "-__v", async (err, house) => {
if (err) { return res.status(400).json(err); }
else if (!house) { return res.status(400); }
house.title = body.house.title;
house.totalSize = parseInt(body.house.totalSize.toString());
house.bathrooms = parseInt(body.house.bathrooms.toString());
house.totalBeds = parseInt(body.house.totalBeds.toString());
house.description = body.house.description;
house.totalFreeBeds = parseInt(body.house.totalFreeBeds.toString());
house.minPrice = parseFloat(body.house.minPrice.toString()).toFixed(2);
house.type = body.house.type;
house.level = body.house.level;
house.top_floor = body.house.top_floor;
house.rooms = body.house.rooms;
house.checkboxes = body.house.checkboxes;
house.contacts = body.house.contacts;
house.pos = body.house.pos;
house.save(err => {
if (err) { console.log(err); return res.status(400).json(err); }
return res.status(200).json({ status: 200, remove: remove });
});
});
Before updating house.shared.photos is ["foo", "bar"]
After is [].
Why?
You are not setting the house.shared anywhere.
Try adding house.shared = body.house.shared before save call.

Nodejs , Mongoose need to optimize query for faster result while query is under loop

Current execution doesn't have any problem but it take alot of time to return result.
House Schema
const HouseSchema = Schema({
wardNumber: Number
})
Family Schema
const FamilydetailSchema = Schema({
house: {
type: Schema.Types.ObjectId,
ref: "house"
},
gender: {
type: String,
required: true
},
})
Query to be optimize
member = async (ward, gender) => {
const family = await families.find(gender, "house").populate({
path: "house",
match: ward,
select: "_id"
});
if (family) {
let count = family.filter(({ house }) => house != null).length || 0;
return count;
}
};
Calling the above function in loop
totalWard = 14;
result = [];
let voidData = [...Array(totalWard).keys()].map(async each => {
const ward = each + 1;
let body = { ward };
body.ward = each + 1;
body.male = await member(ward, { gender: "male" });
body.female = await member(ward, { gender: "female" });
body.third = await member(ward, { gender: "third_gender" });
body.total = await member(ward, {});
result.push(body);
});
await Promise.all(voidData);
It is better to also wrap
body.male = await member(ward, { gender: "male" });
body.female = await member(ward, { gender: "female" });
body.third = await member(ward, { gender: "third_gender" });
body.total = await member(ward, {});
into a promise.all function

Resources