I am creating a database with MongoDB and using the Mongoose ODM. I'm using Node.js. I ran the code without the last block several times and it was fine, but when I wrote the last block in order to use the .find() method, it threw me an odd error.
This is the app.js file:
//require mongoose
const mongoose = require('mongoose');
//connect to mongoDB database
mongoose.connect('mongodb://localhost:27017/albumDB', {useNewUrlParser: true, useUnifiedTopology: true});
//CREATE
//create schema (blueprint/structure)
//of data that we save to the database
const albumSchema = new mongoose.Schema ({
name: String, //the DB has a variable called name with a value of String
author: String,
year: Number,
genre: String,
listened: Boolean,
liked: Boolean
});
//creating the model. parameters: object of collection, schema
const Album = mongoose.model('Album', albumSchema);
//creating the album document
const album = new Album({
name: 'Insurgentes',
author: 'Steven Wilson',
year: 2008,
genre: 'Prog rock',
listened: 1,
liked: 1
});
//save album inside Album inside albumDB
//album.save().then(() => console.log('meow'));
const personSchema = new mongoose.Schema ({
name: String,
age: Number
});
const Person = mongoose.model('Person', personSchema);
const person = new Person({
name: "John",
age: 37
});
//person.save();
const SiameseDream = new Album({
name: 'Siamese Dream',
author: 'The Smashing Pumpkins',
year: 1993,
genre: 'Alt rock, Grunge',
listened: 1,
liked: 1
});
const MellonCollie = new Album({
name: 'Mellon Collie and the Infinite Sadness',
author: 'The Smashing Pumpkins',
year: 1995,
genre: 'Alt rock, Dream pop',
listened: 1,
liked: 1
});
const Adore = new Album({
name: 'Adore',
author: 'The Smashing Pumpkins',
year: 1998,
genre: 'Alt rock, Art rock',
listened: 1,
liked: 1
});
//READ
Album.find(function (err, albums){ //1. error 2.what it finds back
if (err) {
console.log(err);
} else {
console.log(albums);
}
});
This is the error that shows up on my terminal, related to the last block of code:
$ node app.js
TypeError: cursor.toArray is not a function
at model.Query.<anonymous> (C:\Users\user\Desktop\Music\node_modules\mongoose\lib\query.js:2151:19)
at model.Query._wrappedThunk [as _find] (C:\Users\user\Desktop\Music\node_modules\mongoose\lib\helpers\query\wrapThunk.js:27:8)
at C:\Users\user\Desktop\Music\node_modules\kareem\index.js:370:33
at processTicksAndRejections (internal/process/task_queues.js:75:11)
(node:11536) UnhandledPromiseRejectionWarning: MongoInvalidArgumentError: Method "collection.find()" accepts at most two arguments
at Collection.find (C:\Users\user\Desktop\Music\node_modules\mongodb\lib\collection.js:238:19)
at NativeCollection.<computed> [as find] (C:\Users\user\Desktop\Music\node_modules\mongoose\lib\drivers\node-mongodb-native\collection.js:191:33)
at NativeCollection.Collection.doQueue (C:\Users\user\Desktop\Music\node_modules\mongoose\lib\collection.js:135:23)
at C:\Users\user\Desktop\Music\node_modules\mongoose\lib\collection.js:82:24
at processTicksAndRejections (internal/process/task_queues.js:75:11)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:11536) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)(node:11536) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
This issue is facing mongoose version 6.0 So you just have to downgrade the mongoose version. Just run npm uninstall mongoose to uninstall the current mongoose version then run npm i mongoose#5.13.8, this will install the version that will fix your problem. Just check this link https://www.zhishibo.com/articles/132795.html
Mongoose has just updated and in 6+ version
we have to pass the object as first parameter followed by call back function with params of error and result of query!!
To GET ALL records just pass the empty object.
Album.find({}, function (err, result){ // get all albums
if (err) { // if there will be any error
console.log(err);
} else { /// in success case in which records from DB is fetched
console.log(result);
}
});
https://mongoosejs.com/docs/api.html#model_Model.find
Updating to mongoose#6.0.1 fixed the issue for me.
npm run update --save will update all your dependencies including mongoose
Related
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");
}
}});
when i receive the req.query and I pass it to in my insomnia a date value and a make a request all is going fine but when I receive the date it says that is invalid like you see in the screen from my logs I try to see value with console.log, and always when I received it from req.query, even when I use parsedISO, and I dont know why, can someone helps me?
I use isValid to verify my date and it returns false
Here me code and some screens:
const date = req.query;
console.log(date);
const parsedDate = parseISO(date);
const startDay = startOfDay(parsedDate);
const endDay = endOfDay(parsedDate);
const appointments = await Appointment.findAll({
where: [
{
provider_id: req.userId,
canceled_at: null,
date: {
[Op.between]: [startDay, endDay],
},
},
],
order: ['date'],
});
return res.json(appointments);
}
the error returned is:
Executing (default): SELECT "id", "date", "canceled_at", "created_at" AS "createdAt", "updated_at" AS "updatedAt", "user_id", "provider_id" FROM "appointments" AS "Appointments" WHERE (("Appointments"."provider_id" = 2 AND "Appointments"."canceled_at" IS NULL AND "Appointments"."date" BETWEEN 'Invalid date' AND 'Invalid date')) ORDER BY "Appointments"."date";
(node:37307) UnhandledPromiseRejectionWarning: SequelizeDatabaseError: invalid input syntax for type timestamp with time zone: "Invalid date"
at Query.formatError (/Users/dariocoronel/Desktop/practices/Gostack/javascript/repo/backend/api/node_modules/sequelize/lib/dialects/postgres/query.js:386:16)
at Query.run (/Users/dariocoronel/Desktop/practices/Gostack/javascript/repo/backend/api/node_modules/sequelize/lib/dialects/postgres/query.js:87:18)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:37307) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:37307) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Screen from my logs in my code
I want to use RXJS with typescript yeoman generator, according to the docs inquirer which is the engine under yeoman support RXJS
https://github.com/SBoudrias/Inquirer.js/#reactive-interface
I use the following
export default class myGenerator extends Generator {
...
async prompting() {
const prompts = new Subject<Generator.Question>();
await this.prompt(prompts);
prompts.next({
name: "appName",
message: "app name: ",
type: "input",
default: this.props!.appName,
validate(input: string) {
const appName = validateAppName(input);
return !appName[1] ? appName[0] : true;
},
});
prompts.next({
type: "list",
name: "tech",
message: "Which type",
default: "CLI",
choices: [{ name: "CLI" }, { name: "CloudApp" }],
});
prompts.complete();
}
Now while running it I got error :
Error: You must provide a `name` parameter
at InputPrompt.throwParamError (/usr/local/lib/node_modules/yo/node_modules/inquirer/lib/prompts/base.js:73:11)
at new Prompt (/usr/local/lib/node_modules/yo/node_modules/inquirer/lib/prompts/base.js:33:12)
at new InputPrompt (/usr/local/lib/node_modules/yo/node_modules/inquirer/lib/prompts/input.js:11:1)
at PromptUI.fetchAnswer (/usr/local/lib/node_modules/yo/node_modules/inquirer/lib/ui/prompt.js:85:25)
at MergeMapSubscriber._tryNext (/usr/local/lib/node_modules/yo/node_modules/rxjs/internal/operators/mergeMap.js:69:27)
at MergeMapSubscriber._next (/usr/local/lib/node_modules/yo/node_modules/rxjs/internal/operators/mergeMap.js:59:18)
at MergeMapSubscriber.Subscriber.next (/usr/local/lib/node_modules/yo/node_modules/rxjs/internal/Subscriber.js:66:18)
at MergeMapSubscriber.notifyNext (/usr/local/lib/node_modules/yo/node_modules/rxjs/internal/operators/mergeMap.js:95:26)
at InnerSubscriber._next (/usr/local/lib/node_modules/yo/node_modules/rxjs/internal/InnerSubscriber.js:28:21)
at InnerSubscriber.Subscriber.next (/usr/local/lib/node_modules/yo/node_modules/rxjs/internal/Subscriber.js:66:18)
events.js:170
throw er; // Unhandled 'error' event
Im not sure where to put the name as all the prompts are providing the name property. , any idea ?
What I need is to create just two simple questions which will work with RXJS
How I can do that ?
I'm trying to read and write from/to an Azure Cosmos DB with two different bots (js, v4, ms botframework).
Chatbot 1:
- Chat with user, save user data and use it later
Chatbot 2:
- Read and display some user data
I use the following client: https://github.com/Microsoft/BotFramework-WebChat
Scenario:
I fixate my userID in the client (which has a directline to bot 1) to let's say "123"
I use Bot 1 and enter my username in the dialog (prompted by bot)
I refresh the Website on which Bot 1 is running with the same id "123"
I see that the bot still has my data stored
I change the ID in my client to "124"
I use Bot 1 and see there is no stored data (which is expected since ID "124" has never chatted with Bot 1)
I change the ID back to "123"
I use bot 1 and see that data from step 2 is still there
I use bot 2 with the id "123"
I see that there is no data ("undefined")
I use bot with ID "123" again
I see that the data from step 2 is gone
Which means that whenever I access the database with my second bot it seems like the data is cleared / deleted.
This is how I access the DB in index.js:
//Add CosmosDB (info in .env file)
const memoryStorage = new CosmosDbStorage({
serviceEndpoint: process.env.ACTUAL_SERVICE_ENDPOINT,
authKey: process.env.ACTUAL_AUTH_KEY,
databaseId: process.env.DATABASE,
collectionId: process.env.COLLECTION
})
// ConversationState and UserState
const conversationState = new ConversationState(memoryStorage);
const userState = new UserState(memoryStorage);
// Use middleware to write/read from DB
adapter.use(new AutoSaveStateMiddleware(conversationState));
adapter.use(new AutoSaveStateMiddleware(userState));
This is how I use the DB in bot.js:
constructor(conversationState, userState, dialogSet, memoryStorage) {
// Creates a new state accessor property.
// See https://aka.ms/about-bot-state-accessors to learn more about the bot state and state accessors
this.conversationState = conversationState;
this.userState = userState;
// Memory storage
this.memoryStorage = memoryStorage;
// Conversation Data Property for ConversationState
this.conversationData = conversationState.createProperty(CONVERSATION_DATA_PROPERTY);
// Properties for UserState
this.userData = userState.createProperty(USER_DATA_PROPERTY);
this.investmentData = userState.createProperty(INVESTMENT_DATA_PROPERTY);
}
async displayPayout (step) {
console.log("Display Payout");
// Retrieve user object from UserState storage
const userInvestData = await this.investmentData.get(step.context, {});
const user = await this.userData.get(step.context, {});
await step.context.sendActivity(`Hallo ${user.name}. Am Ausgang kannst du dir deine Bezahlung von ${userInvestData.payout} abholen.` );
}
The code snipped is from bot 2. Bot 1 saves the data in the same way. You can find the repos here:
Bot 1: https://github.com/FRANZKAFKA13/roboadvisoryBot
Bot 2: https://github.com/FRANZKAFKA13/displayBot
Client for Bot 1: https://github.com/FRANZKAFKA13/ra-bot-website-c
Client for Bot 2: https://github.com/FRANZKAFKA13/ra-bot-website-display
I also tried to use the "readOnly" key from CosmosDB in bot 2, which throws an error:
[onTurnError]: [object Object]
(node:1640) UnhandledPromiseRejectionWarning: TypeError: Cannot perform 'set' on a proxy that has been revoked
at adapter.sendActivities.then (C:\Users\X\Implementierung\display_bot\node_modules\botbuilder-core\lib\turnContext.js:175:36)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:229:7)
(node:1640) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 3)
Another behavior that I have noticed: When I trigger a "join event" through my client with a redux store, the userdata is not saved as well (every time I refresh the page, the data is gone, despite using the same id "123" all the time)
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
// Event starting bot's conversation
name: 'webchat/join',
value: {}
}
Any ideas? Thanks in advance
Since storage ids (see image) are created automatically based off of user ids (that may also be created automatically and varies by channel) and channel ids, this can be very difficult to do. It can make it very difficult to persist user and conversation data, particularly across bots and channels.
Example ID:
Here's more on how IDs work.
Personally, I would write my own, custom storage, instead of (or in addition to) saving it with UserState.
To write your data, do something like this:
const changes = {};
const userDataToWrite = {
name: step.result,
eTag: '*',
}
// Replace 'UserId' with however you want to set the UserId
changes['UserId'] = userDataToWrite;
this.memoryStorage.write(changes);
This will store a document that looks like this (I set 'UserId' to 'user123':
To read:
const userDataFromStorage = await this.memoryStorage.read(['UserId']);
userDataFromStorage will look like this:
{ UserId:
{ name: 'myName',
eTag: '"0000c700-0000-0000-0000-5c7879d30000"' } }
You'll have to manage userIds yourself, but this will ensure that the data can be read across bots, channels, and users.
Edit: Solved it by adding "[this.userID]" after each "user" call.
I tried your method and whenever I write the data, a new eTag is created which leads to the object being split apart:
"document": {
"25781dc4-805d-4e69-bf89-da1f4d72e7cb": {
"25781dc4-805d-4e69-bf89-da1f4d72e7cb": {
"25781dc4-805d-4e69-bf89-da1f4d72e7cb": {
"25781dc4-805d-4e69-bf89-da1f4d72e7cb": {
"25781dc4-805d-4e69-bf89-da1f4d72e7cb": {
"name": "",
"age": "",
"gender": "",
"education": "",
"major": "",
"eTag": "\"00003998-0000-0000-0000-5c797fff0000\""
},
"name": "Jane Doe",
"eTag": "\"00003e98-0000-0000-0000-5c7980080000\""
},
"age": 22,
"eTag": "\"00004898-0000-0000-0000-5c7980150000\""
},
"gender": "female",
"eTag": "\"00004d98-0000-0000-0000-5c79801b0000\""
},
"education": "Bachelor",
"eTag": "\"00005498-0000-0000-0000-5c7980200000\""
},
"major": "Business Administration",
"complete": true
How can I prevent this?
My Code:
In Constructor:
this.changes = {};
this.userID = "";
this.userDatax = {
name: "",
age: "",
gender: "",
education: "",
major: "",
eTag: '*',
}
In Dialogs:
async welcomeUser (step) {
console.log("Welcome User Dialog");
//step.context.sendActivity({ type: ActivityTypes.Typing});
// Initialize UserData Object and save it to DB
this.changes[this.userID] = this.userDatax;
await this.memoryStorage.write(this.changes);
}
async promptForAge (step) {
console.log("Age Prompt");
// Read UserData from DB
var user = await this.memoryStorage.read([this.userID]);
console.log(user);
// Before saving entry, check if it already exists
if(!user.name) {
user.name = step.result;
user.eTag = '*';
// Write userData to DB
this.changes[this.userID] = user;
await this.memoryStorage.write(this.changes);
}
}
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