Mongoose currency does not show decimals - javascript

I am trying to create a Schema with a 'price' field using Mongoose currency and follow the documentation on it. However the output does not show two decimals (499 instead of 4.99). If I use console.log to print the price, it shows the desired results, with two decimals. I wonder whether I misunderstood the Mongoose documentation on Currency or does the cause lie somewhere else.
This is my schema.
var mongoose = require('mongoose');
var assert = require('assert');
var Dishes = require('./models/stackmodel');
// Connection URL
var url = 'mongodb://localhost:27017/conFusion';mongoose.connect(url);
var db = mongoose.connection;
var product = new Dishes({ price: '4.99' });
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
// we're connected!
console.log("Connected correctly to server");
// create a new dish
Dishes.create({
name: 'Uthapizza',
price: (product.price/100).toFixed(2),
}, function (err, dish) {
if (err) throw err;
console.log('Dish created!');
console.log(dish);
console.log(typeof (product.price/100).toFixed(2));
console.log((product.price/100).toFixed(2));
db.collection('dishes').drop(function () {
db.close();
});
});
});
This is my model.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
require('mongoose-currency').loadType(mongoose);
var Currency = mongoose.Types.Currency;
// create a schema
var dishSchema = new Schema({
name: {
type: String,
required: true,
unique: true
},
price: {
type: Currency,
require: true,
min: -20000,
max: 50000,
default: ''
}
});
var Dishes = mongoose.model('Dish', dishSchema);
// make this available to our Node applications
module.exports = Dishes;
And this is the print-out.
C:\ass2>node stack
Connected correctly to server
Dish created!
{ __v: 0,
name: 'Uthapizza',
_id: 58cd3dbd4319c51264489d8d,
price: 499 }
string
4.99
C:\ass2>
I have searched on the web, including on this site, but found no solution so far.
I use:
OS is Windows 7 32-bit
mongoose#4.8.6
node version v6.10.0
and while running npm list I got the following message (I suspect this might be the reason why I got the above problem):
npm ERR! extraneous: currency#3.0.0 C:\node_modules\currency
npm ERR! extraneous: mocha#3.2.0 C:\node_modules\mocha
npm ERR! extraneous: mongoose-currency#0.2.0 C:\node_modules\mongoose-currency
Thank's a lot beforehand.

Fairly late to the party but for future folks, this is how mongoose-currency stores float values. It first multiplies by 100 and then stores it. You should divide by 100 when retrieving values.
According to their readme on GitHub:
Saves a String as an integer (by stripping non-digits and multiplying by 100) to prevent rounding errors when performing calculations (See gotchas for details)
Example:
var product = new Product({ price: "$1,200.55" });
product.price; // Number: 120055
product.price = 1200;
product.price; // Number 1200 It will not round or multiply. Stored AS IS and should represent $12.00

Related

Mongoose cannot .insertMany()

I've looked everywhere and I cannot figure out why I get this error while I try to create and save documents with Mongoose.
It has worked to save individual documents with await fruit.save();, but when I run the script to add multiple documents with .insertMany() I get the following message in terminal and I have no clue what to do with it.
/Users/FruitsProjectMongoose/node_modules/mongoose/lib/model.js:3519
for (let i = 0; i < error.writeErrors.length; ++i) {
^
TypeError: Cannot read properties of undefined (reading 'length')
at /Users/FruitsProjectMongoose/node_modules/mongoose/lib/model.js:3519:47
at collectionOperationCallback (/Users/FruitsProjectMongoose/node_modules/mongoose/lib/drivers/node-mongodb-native/collection.js:194:24)
at /Users/FruitsProjectMongoose/node_modules/mongodb/lib/utils.js:349:66
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
It would be an understatement to say that I have tried everything that I could think of/find across the web. I’ve messaged a few devs. and they’ve recommended me to try some things but no luck. I really need some help with this. I start to think it might be something wrong with my system.
I’ve installed MongoDB through Homebrew and Mongoose through npm in the past two days so everything is up-to-date.
The fruitsDB exists and I am able to access and view the collections and the individually added documents through the MongoDB shell mongosh.
Here is my simple JS script:
const mongoose = require("mongoose");
mongoose.set('strictQuery', false);
// Connect to MongoDB by port and catch errors.
main().catch(err => console.log(err));
async function main() {
await mongoose.connect('mongodb://127.0.0.1:27017/fruitsDB')
.then(() => console.log('Connected!'));
// Defining a Model Schema.
const Schema = mongoose.Schema;
const fruitSchema = new Schema({
name: {
type: String,
require: true
},
rating: {
type: Number,
require: true
},
review: {
type: String,
require: true
}
});
const peopleSchema = new Schema({
name: String,
age: Number
});
// Create a Model.
const Fruit = new mongoose.model("Fruit", fruitSchema);
const People = new mongoose.model("People", peopleSchema);
// Create & Save a Document.
const fruit = new Fruit({
name: "Banana",
rating: 10,
review: "Perfection!"
});
// await fruit.save();
const people = new People({
name: "Eduard",
age: 25
});
// await people.save();
// Create & Save docs. in Bulk.
const kiwi = new Fruit({
name: "Kiwi",
rating: 9,
review: "Great, kinda expensive!"
});
const orange = new Fruit({
name: "Orange",
rating: 6,
review: "Too sweet."
});
const apple = new Fruit({
name: "Apple",
rating: 7,
review: "Great fruit!"
});
Fruit.insertMany([kiwi, orange, apple], function(err) {
if (err) {
console.log(err);
} else {
console.log("Succesfully saved to fruitsDB");
}
});
mongoose.connection.close();
};
MongoDB server is running on brew services start mongodb-community.
This error is likely caused by an issue with the Mongoose library. To fix it, try updating the Mongoose library to the latest version. You can do this by running the following command in your terminal:
npm install mongoose#latest --save
If the "error" object is not defined, make sure that it is properly initialized before attempting to access its properties.
I've missed a set of curly braces. So the correct syntax is this.
await Fruit.insertMany([kiwi, orange, apple], {function(err) {
if (err) {
console.log(err);
} else {
console.log("Succesfully saved to fruitsDB");
}
}});

Attempt to search for a specific string

I'm trying to find a specific row in the database based on the user's message, namely: catalystname.
Within the schema I have successfully indexed the given string as text:
const { Schema } = mongoose;
const scheduleMessageSchema = new Schema({
_id: { type: Schema.Types.Oid, auto: true },
catalystname: String,
catalystdesc: String,
catalystquest: String,
date: String,
});
scheduleMessageSchema.index({catalystname: 'text'});
module.exports = mongoose.model('dbcatalyst', scheduleMessageSchema);
My search code:
const Catal = require("../src/models/dbcatalyst.js")
module.exports.run = async (client, message, args) => {
message.content = args.slice(0).join(" ")
Catal.find({$text: {$search: message.content}})
.exec(function(docs){
let embedlogs3 = new Discord.RichEmbed()
.setAuthor(`1`, message.author.displayAvatarURL)
.setDescription(`${docs}`)
.setColor("#33ffff")
message.channel.send(embedlogs3)
/*/ ${collected.first().content}/*/
});
}
And started searching for the required line in the message. The bot successfully copes with its task, but displays the entire document in full instead of 1 line.
_id: 5e243704961eb23c106bfb02,
catalystname: 'Чёрный Коготь',
catalystdesc: '0',
catalystquest: '0',
date: '1579430157018',
__v: 0
}
Can I somehow output exactly the string? catalystname
Looking at the Mongoose documentation, it seems the callback takes two parameters:
err An error or null
docs The returned document(s)
Change your callback to
Catal.find({$text: {$search: message.content}})
.exec(function(err, docs){
...
});
and you should receive an array of matching documents.

How to save my data on mongoDB by using expressjs?

I am a beginner in Backend developing, and I have this array called (Movie). I use expressJS and I want to save the array on MongoDB.I will use Mongodb atlas for my database. I appreciate your help
I tried to follow this instruction on this website:
https://medium.com/#lavitr01051977/node-express-js-aea19636a500
I ignored the first steps and starts from ( Connecting to the Database ) title but It doesn't work.
var express = require('express')
var app = express()
app.get('/', (req, res) => {
res.send('ok')
});
//movie array
const movies = [
{ title: 'Jaws', year: 1975, rating: 8 },
{ title: 'Avatar', year: 2009, rating: 7.8 },
{ title: 'Brazil', year: 1985, rating: 8 },
{ title: 'الإرهاب والكباب‎', year: 1992, rating: 6.2 }
]
//read the array movie
app.get('/movies/read/',(req,res) => {
res.send({status:200, data:movies})
})
//add elements to array movies
app.get('/movies/add',(req,res) => {
var t = req.query.title
var y = req.query.year
var r = req.query.rating
if(t == undefined || y == undefined || y.length > 4 || isNaN(y)) {
res.send({status:403, error:true, message:'you cannot create a movie without providing a title and a year'})
}
if (r == "") {
r = 4
}
movies.push({title: t, year: y, rating: r})
res.send({status:200, data:movies})
})
//delete elements from array movies
app.get('/movies/delete/:ID',(req,res) => {
var d = req.params.ID
if (d > 0 && d < movies.length ) {
movies.splice(d-1, 1)
res.send({status:200, message: movies})
}
else {
res.send({status:404, error:true, message:'the movie <ID> does not exist'})
}
})
//update elements from array movies
app.get('/movies/update/:ID',(req,res) => {
let c = req.params.ID
let x = req.query.title
let y = req.query.year
let z = req.query.rating
function update(a, b) {
if(a != undefined || a == "") {
movies[c-1][b] = a
}
}
if(c > 0 && c < movies.length ) {
update(x, 'title')
update(y, 'year')
update(z, 'rating')
res.send({status:200, message: movies})
}
else {
res.send({status:404, error:true, message:'the movie <ID> does not exist'})
}
})
app.listen(3000, () => console.log('listinig on port 3000'))
I expect the answer is like the link that I put it above on medium.com website
mongoose is a framework that facilitates interacting with MongoDB. Actually you basically never want to do all the validation, casting, and logic boilerplate on your own, so why reinvent the wheel.
And since you're a beginner, don't be afraid of frameworks. There are many useful frameworks for many areas of backend and frontend to make life easier for you.
The article you shared is self-explanatory, but I will sum up only the database part for you (I won't go deep into your code, no donkey work. the rest is up to you):
1) First of all install mongoose.
npm install mongoose
The article has --save which is no need to add anymore, as "npm install saves any specified packages into dependencies by default."(ref.)
2) to able to access and use mongoose, you need to import it, in node way, that is require().
const express = require(‘express’)
const mongoose = require(“mongoose”);
const bodyParser = require(‘body-parser’);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
And what's body-parser there for?
When dealing with database in express, you'll sooner or later come across errors like this one.
and the reason why we need one after all is best explained in this answer.
Also, recent versions of express has its own body parser now, so you can use app.use(express.json()) instead of app.use(bodyParser.json()).
Important: body-parser must be before your routes.
3) use mongoose.connect(url).
url argument is what you find in your MongoDB Atlas. :
Location: clusters tab -> connect -> connect your application -> driver node.js
Which gives you, something like this:
mongodb+srv://<user>:<password>#,cluster>.mongodb.net/test?retryWrites=true&w=majority
Important: you use user and password of the user you made within Database Access tab, not your own user and password.
You can set up your environment variables to secure sensitive and changeable data. But I prefer using config.js for simplicity, and which usually resides in the root of app.
Not only you can secure them (like for using .gitignore), but also easily modify them as there are variables that might change from one environment to another environment, making them available in one place and easy to find, instead of looking for them to change all over your app.
For .env file approach, read this article.
Important: in case you want to put your code in github or anywhere online, which one reason we use config.js, don't forget to add this file in .gitignore to avoid such sensitive data get leaked and exposed to others online.
in config.js you can do so:
exports.username = 'your user';
exports.pass = 'your pass';
exports.myCluster = 'your cluster's name';
Then import them so:
const { username, pass, myCluster } = require('./config'); <- the path might be different for you!
Tip: You can use back-tick (` `) to easily insert those variables for const url, through interpolation.
That is:
const url = `mongodb+srv://${username}:${password},${myCluster}.mongodb.net/test?retryWrites=true&w=majority`
Important: make sure to whitelist your IP from MongoDB side (atlas), otherwise you will get connection error.
Under security: Network Access -> IP Whitelist
You could use 0.0.0.0/0 to whitelist all IPs.
Also, when using VPN, your IP will change too.
4) last but not least, after connecting to database, you need to define your schema:
const moviesSchema = new mongoose.Schema({
title: String,
year: Number,
rating: Number
});
And
const Movies = mongoose.model(“Movies”, moviesSchema);
Tip: A common mistake many newbies make is that they forgot to use new:
new mongoose.Schema({...})
If you want to create your model in a separate file (which is the best practice), you will need to modify your const Movies so:
module.exports = mongoose.model(“Movies”, moviesSchema);
Don't forgot to add const mongoose = require('mongoose'); in that separate js model file.
And in wherever you use want to use this model, you import so:
const Movies= require('../models/movies'); (the path may different for your app)
The rest, my friend, is up to you. What you want to do with your database and how to use it.
Note to others: I put so much time and mind to this as I was writing this. Please, if you see something wrong, or think you can add something, feel free to edit and improve my answer.
I would suggest you to take look at mongoose framework to interact with a Mongo database using NodeJS.
However, in the code you've provided you're not interacting with any database. You would need to define a Schema and then you could save a new doc or do any other action with your collection. Please follow some 'Get started' guide on how to do it.
Hope it helps!
I ll explain step by step. NOTE THAT THIS PROCESS SHOULD BE RUN ONLY ONCE. SO YOU SHOULD ADD THIS CODE TO A SEPARATE MODULE AND RUN IT ONCE. otherwise you will keep adding more items to the db. lets name this module
movies.js
//you need to connect to mongodb through mongoose.
const mongoose = require("mongoose");
mongoose
.connect("mongodb://127.0.0.1:27017/movies", { //will create movies db automatically
useNewUrlParser: true,
useCreateIndex: true
})
.catch(err => {
console.log(err.message);
process.exit(1);
})
.then(() => {
console.log("connected");
});
//next create a schema and model:
const movieSchema = new mongoose.Schema({
title: String,
year: Number,
rating: Number
});
const Movie = mongoose.model("Movie", movieSchema);
//create movies array based on `Movie model` so u can use save() method.
const movies = [
new Movie({ title: "Jaws", year: 1975, rating: 8 }),
new Movie({ title: "Avatar", year: 2009, rating: 7.8 }),
new Movie({ title: "Brazil", year: 1985, rating: 8 }),
new Movie({ title: "الإرهاب والكباب‎", year: 1992, rating: 6.2 })
];
//Last step save it.
movies.map(async (p, index) => {
await p.save((err, result) => {
if (index === movies.length - 1) {
console.log("DONE!");
mongoose.disconnect();
}
});
});
map is an array method.it iterates over array and save each item inside the array. Once every item in the array is saved we need to disconnect from db. array method takes 2 arguments. on is each item inside the array, second one is the index of each item. index in array starts from 0, so last item's index in movies array is 3 but length of the array is 4 so once 4-1=3 that means we saved every item in the array.
Now run the code
node movies.js

Mongoose seems to fail quietly

So have a completely separate issue (I think) which is saving an array to a mongo document. So I took out that part, created a data structure that would have the same issue to try to resolve it. But now my test code seems to finish before the save function returns, just not certain how to resolve either issue, or if they potentially are connected.
The mongoose schema:
var mongoose = require('mongoose');
ObjectId = mongoose.Schema.Types.ObjectId;
var offerSchema = mongoose.Schema({
closeDate: Date,
settleDate: Date,
schemaVersion: Number,
_offered: [{ type: ObjectId, ref: 'User'}], //Ids of thos offered
_offerDate: { type: Date },// The date they where offered
_accepted: [{ type: ObjectId, ref: 'User'}],//Ids of those accepted
_acceptedDate: [{ type: Date }], //Dates when accepted
});
// create the model for users and expose it to our app
module.exports = mongoose.model('offer', offerSchema);
So I have written the code below to recreate the issue, the below code should work but not store a value in _offered.
var offer = require('../models/offerSchema.js')
var indata = {"offer":{"closeDate":"2015-08-31T13:26:36.512Z","settleDate":"2015-08-31T13:26:36.512Z","type":1,"_offered":[{"id":"55dc7994ed0fcf4a58d4a689"},{"id":"55dcd30915e3be545a51bebd"}],"_offerDate":"2015-08-31T13:26:36.512Z"}}
var thisOffer = indata.offer
for ( var i in thisOffer ){
console.log("Got "+ i +" is " + thisOffer[i])
}
var myOffer = new offer(thisOffer);
myOffer._offered = undefined
var promise =
myOffer.save(function(err){
if(err){
console.log('Got an error: ' + err)
}
console.log('Got an id: ' + myOffer._id)
return 0;
}).then(function() {
console.log("I get here and quit?");
})
However, the code seems to complete before the save have completed, and I am actually not certain how to avoid this.
You are mixing logic with callbacks and promises. So you do not need the callback, just act on the promise returned:
myOffer._offered = undefined
myOffer.save()
.then(function() {
console.log("I get here and quit?");
})
.then(null,function(err) {
console.log(err);
});
I noticed you made another attempt using Bluebird promises, but it is not necessary as if you implement as shown here any errors will be appropriately routed.
Threre are notes that mongooose 5.x is slated to have a more standardised approach to promises and/or directly use Bluebird promises when configured
OK, found the issue. mongoose save is not promisified (or at least that is what I recon the issue is), changed the first part to use bluebird for promises, then changed the save to use saveAsync as below
Schema (and connection, and bluebird)
var mongoose = require('mongoose');
var Promise = require('bluebird');
Promise.promisifyAll(mongoose);
mongoose.connect('mongodb://webbetcha:M0t0rWrl3d#localhost/betchadb');
ObjectId = mongoose.Schema.Types.ObjectId;
var offerSchema = mongoose.Schema({
closeDate: Date,
settleDate: Date,
schemaVersion: Number,
_offered: [{ type: ObjectId, ref: 'User'}], //Ids of thos offered
_offerDate: { type: Date },// The date they where offered
_accepted: [{ type: ObjectId, ref: 'User'}],//Ids of those accepted
_acceptedDate: [{ type: Date }], //Dates when accepted
});
// create the model for users and expose it to our app
module.exports = mongoose.model('offer', offerSchema);
And the code
var offer = require('../models/offerSchema.js');
var indata = {"offer":{"closeDate":"2015-08-31T13:26:36.512Z","settleDate":"2015-08-31T13:26:36.512Z","type":1,"_offered":[{"id":"55dc7994ed0fcf4a58d4a689"},{"id":"55dcd30915e3be545a51bebd"}],"_offerDate":"2015-08-31T13:26:36.512Z"}}
var thisOffer = indata.offer
for ( var i in thisOffer ){
console.log("Got "+ i +" is " + thisOffer[i])
}
var myOffer = new offer(thisOffer);
myOffer._offered = undefined
myOffer.saveAsync()
.then(function(doc){
console.log('Got an id: ' + myOffer._id)
})
.catch(function(err){
if(err){
console.log('Got an error: ' + err)
}
});

How to manipulate data returned from mongo db using mongoose

I've created a local database using mongo (using this tutorial actually)
It has a db named 'simple' and collection named 'people'. Then I import json with each element as
{
"id": 1,
"guid": "1581cfde-f2fc-44f8-8953-511331e943ab",
"isActive": true,
"firstName": "Ilene",
"lastName": "Kent",
"email": "carolegoodman#intrawear.com"
}
I then create the schema and Person model in my node app
var express = require('express');
var path = require('path');
var mongoose = require('mongoose');
var app = express();
app.set('port', (process.env.PORT || 5000));
mongoose.connect('mongodb://localhost/simple')
var personSchema = {
firstname: String,
lastname: String,
email: String
}
var Person = mongoose.model('Person', personSchema, 'people')
app.get('/users', function(req,res){
Person.find(function(err, doc){
var x = doc[0]
console.log(x)
console.log(Object.keys(x))
res.send(200);
});
});
On calling find() on the Person model I get logged (for console.log(doc[0])) - the first item in the doc returned:
{ _id: 548e41afa0bad91d53f34cce,
id: 0,
guid: 'af6a931d-1801-4662-9d52-c95dc97bac22',
isActive: false,
firstName: 'Janna',
lastName: 'Shelton',
email: 'crossoconnor#geekology.com' }
But my problem is that when I look for the property firstName on doc[0] (i.e. doc[0].firstName) I get an undefined.
I've tried diagnosing this and Object.keys(doc[0]) gives me:
[ '$__',
'isNew',
'errors',
'_maxListeners',
'_doc',
'_pres',
'_posts',
'save',
'_events' ]
meaning I suspect there must be some special methods for mongoose when you want to access the data from your returned elements - but I can't find the answer in documentation or here.
Thanks
You receive an array of Documents. Mongoose API
doc[0].get('firstName')
When you just want a plain JavaScript representation of the documents that you can freely manipulate, add lean() to your Mongoose query chain:
app.get('/users', function(req,res){
Person.find().lean().exec(function(err, docs){
var x = docs[0]
console.log(x)
console.log(Object.keys(x))
res.send(200);
});
});
Use .lean() in your query as below.
db.collection.find().lean().then(function(data){})

Categories