I'm using shortid package to shorten my URLs.
Currently, user have this kind of url: https://bucard.co.il/digitalCard/5edd4112eb6ba017d8a4595c (the long string is the _id),
and I want to make it like this: https://bucard.co.il/digitalCard/Y2i1_53Vc
So, I added ShortID field, and as in the documantion, I did this in models/VisitCard.js:
const mongoose = require('mongoose');
const shortid = require('shortid');
const VisitCardsSchema = mongoose.Schema({
ShortID: {
type: String,
default: shortid.generate
},
....
});
module.exports = mongoose.model('VisitCards', VisitCardsSchema);
And my get request in routes/VisitCard.js:
// Get a specific visit card
router.get('/:visitCardId', async (req, res) => {
try {
let cardShortId = req.params.visitCardId;
let allVisitCards = await VisitCard.find({}); // That's how I saw that all the values changed after every get request.
let visitCard = await VisitCard.findOne({ ShortID: cardShortId }); // Never found the card by the short id - even after coping the short id from above, after the next try it changes.
if (!visitCard) {
return res.status(404).json({
message: 'Not existing card.'
});
} else {
return res.status(200).json(visitCard);
}
} catch (error) {
console.log(error);
return res.status(404).json({
message: 'Some server issue accured...'
});
}
});
Now, the proplem is where after every refresh of the browser or another get request, all the ShortID's of all cards are changing (generated again). I want instead that the short url will not be refreshes after every restart of the server, and it will be stored in the Database.
How can I do that after each card gets it's shortID (by default) it will directlly be stored in the DB ?
By the way, I could just have that after every submits of visit card to put some random string to be stored with the other paramters, but I already have visit cards of users in my service.
THANK YOU !!!
Tried reproducing your issue:
const mongoose = require("mongoose");
const shortid = require("shortid");
mongoose.connect("mongodb://localhost/test9999", {
useNewUrlParser: true
});
const db = mongoose.connection;
db.on("error", console.error.bind(console, "connection error:"));
db.once("open", async function() {
await mongoose.connection.db.dropDatabase();
// we're connected!
console.log("Connected");
const VisitCardsSchema = mongoose.Schema({
name: String,
ShortID: {
type: String,
default: shortid.generate
}
});
const VisitCard = mongoose.model("VisitCard", VisitCardsSchema);
const v1 = new VisitCard({name: "abc"});
const v2 = new VisitCard({name: "cde"});
await v1.save();
await v2.save();
await VisitCard.find(function(err, vcs) {
if (err) return console.error(err);
console.log(vcs);
});
console.log("VCS second call:");
await VisitCard.find(function(err, vcs) {
if (err) return console.error(err);
console.log(vcs);
});
});
Apparently, it works perfectly fine. I even commented part with dropping db for a moment and values are persisted correctly.
The problem must be somewhere else - you sure you do not drop the db or the collection with each GET request somewhere else in the code?
This one: await mongoose.connection.db.dropDatabase(); drops entire db, mongooseconnection.connection.db.dropCollection drops a collection. Check if you can find such lines somewhere in your code.
Related
I need some help with mongodb.
I just started using it, and made a Cluster called db, with a database called discord-bot with a collection called users
This should make a database entry for every user, so here is my code
const { MongoClient } = require("mongodb");
const uri = "mongodb+srv://<My username>:<My password>#<My db url>?retryWrites=true&w=majority";
const client = new MongoClient(uri);
async function run(query) {
try {
await client.connect();
const database = client.db('discord-bot');
const collection = database.collection('users');
await collection.insertOne(query);
} finally {
await client.close();
}
}
botClient.users.cache.forEach(u => {
const q = { name: u.username }
run(q).catch(console.dir);
})
I think this code should work, but it is giving me this error
TypeError: Cannot read property 'maxWireVersion' of null
I can not find anything online about that error, can somebody help me figure out what that error is and how to fix it. (Also, i am using mongodb with discord.js, incase that is neccessary info)
I use this to connect to mongo DB
const MongoClient = require('mongodb').MongoClient;
var connection;
MongoClient.connect('your-db-uri', { useUnifiedTopology: true }, async function(err, client) {
if(err)throw err
console.log("Successfully Connected")
connection = client
})
Then you can use connection variable as global for all functions
My problem is quite peculiar, as I believe to have done everything "by the book".
I'm able to successfully connect to a MongoDB cluster I've created through MongoDB Atlas. When I make a 'POST' request to save a choice that was picked from an array of choices, I successfully create a document through the Model specified below. I then try to save that document to MongoDB by calling the 'save()' method, but it hangs and nothing comes out of it (even if I use a 'catch' to see if any errors occurred).
I'm completely lost as to what is wrong, and what I need to do to solve this. I was hoping you could give me some pointers.
MongoDB connection, schema, and model:
const mongoose = require('mongoose');
const URL = process.env.MONGODB_URL;
mongoose.connect(URL, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => {
console.log('Successfully connected to our MongoDB database.');
}).catch((error) => {
console.log('Could not connect to our MongoDB database.', error.message);
});
const choicesMadeSchema = new mongoose.Schema({
allChoices: Array,
pickedChoice: String
});
const ChoiceMade = mongoose.model('ChoiceMade', choicesMadeSchema);
module.exports = ChoiceMade; // Exports our 'ChoiceMade' constructor, to be used by other modules.
index.js:
/* 1 - Setting things up */
require('dotenv').config();
const express = require('express');
const server = express();
const PORT = process.env.PORT;
const parserOfRequestBody = require('body-parser');
server.use(parserOfRequestBody.json());
/* 2 - Retrieving all the data we need from our 'MongoDB' database */
// Imports the 'mongoose' library, which will allow us to easily interact with our 'MongoDB' database.
const mongoose = require('mongoose');
// Imports our 'ChoiceMade' constructor.
const ChoiceMade = require('./database/database.js');
// Will hold the five latest choices that have been made (and thus saved on our 'MongoDB' database).
let fiveLatestChoicesMade;
// Retrieves the five latest choices that have been made (and thus saved on our 'MongoDB' database).
ChoiceMade.find({}).then((allChoicesEverMade) => {
const allChoicesEverMadeArray = allChoicesEverMade.map((choiceMade) => {
return choiceMade.toJSON();
});
fiveLatestChoicesMade = allChoicesEverMadeArray.slice(allChoicesEverMadeArray.length - 5).reverse();
console.log("These are the five latest choices that have been made:", fiveLatestChoicesMade);
mongoose.connection.close();
});
/* 3 - How the server should handle requests */
// 'GET' (i.e., 'retrieve') requests
server.get('/allChoicesMade', (request, response) => {
console.log("This is the data that will be sent as a response to the 'GET' request:", fiveLatestChoicesMade);
response.json(fiveLatestChoicesMade);
});
// 'POST' (i.e., 'send') requests
server.post('/allChoicesMade', (request, response) => {
const newChoiceMadeData = request.body;
if (Object.keys(newChoiceMadeData).length === 0) {
return response.status(400).json({ error: "No data was provided." });
}
const newChoiceMade = new ChoiceMade({
allChoices: newChoiceMadeData.allChoices,
pickedChoice: newChoiceMadeData.pickedChoice
});
console.log("This is the new 'choice made' entry that we are going to save on our 'MongoDB' database:", newChoiceMade); // All good until here
newChoiceMade.save().then((savedChoiceMade) => {
console.log('The choice that was made has been saved!');
response.json(savedChoiceMade);
mongoose.connection.close();
}).catch((error) => {
console.log('An error occurred:', error);
});
});
/* 4 - Telling the server to 'listen' for requests */
server.listen(PORT, () => {
console.log("Our 'Express' server is running, and listening for requests made to port '" + PORT + "'.");
});
SOLUTION TO THE PROBLEM
In my code's section 2, I was mistakenly closing the connection upon retrieving all the data I need to make my app work. I was doing this (...)
// Retrieves the five latest choices that have been made (and thus saved on our 'MongoDB' database).
ChoiceMade.find({}).then((allChoicesEverMade) => {
const allChoicesEverMadeArray = allChoicesEverMade.map((choiceMade) => {
return choiceMade.toJSON();
});
fiveLatestChoicesMade = allChoicesEverMadeArray.slice(allChoicesEverMadeArray.length - 5).reverse();
console.log("These are the five latest choices that have been made:", fiveLatestChoicesMade);
mongoose.connection.close(); // This should not be here!!!
});
(...) when I should be doing
// Retrieves the five latest choices that have been made (and thus saved on our 'MongoDB' database).
ChoiceMade.find({}).then((allChoicesEverMade) => {
const allChoicesEverMadeArray = allChoicesEverMade.map((choiceMade) => {
return choiceMade.toJSON();
});
fiveLatestChoicesMade = allChoicesEverMadeArray.slice(allChoicesEverMadeArray.length - 5).reverse();
console.log("These are the five latest choices that have been made:", fiveLatestChoicesMade);
// Now that I don't have mongoose.connection.close(), everything's OK!
});
Basically, and in my particular case, I was closing my connection to the MongoDB database after retrieving data from it, and then trying to add a new record to it when I didn't have a connection to it anymore.
I am writing a web application that uses asynchronous database requests as a part of the api. Currently, I have an async express route that awaits function returns from async functions. Both of these functions return booleans and both query the database. One works correctly, however the second one does not.
Here is the MongoClient setup:
const MongoClient = require('mongodb').MongoClient;
const uri = config.uri; // Contains custom url for accessing database
const client = new MongoClient(uri, { useUnifiedTopology: true}, { useNewUrlParser: true }, { connectTimeoutMS: 30000 }, { keepAlive: 1});
where config is from a file imported as.
const config = require("./config.js");
and functions properly.
Here is the express setup:
app.post("/signup", async function(request, response) {
log("POST request at /signup");
log("BEFORE UNIQUE USER");
const isUniqueUser = await validateUniqueUser(request.body.email, request.body.password);
log(isUniqueUser);
const status = {
status: null
};
if (isUniqueUser) {
log("AFTER UNIQUE USER");
let userCreated = await createPracticeProfile(request.body.email, request.body.password);
log("user created: " + userCreated);
if (userCreated) {
status.status = "user_created";
}
response.json(status);
} else {
response.json(status);
}
console.log("********************************end");
});
The console outputs:
BEFORE UNIQUE USER
true (which it should be)
AFTER UNIQUE USER
MongoError: Topology is closed.
user created: undefined
***...***end
Here is the function for validating that a user is unique:
/* VALIDATE_UNIQUE_USER
USE: ensure user does not have existing profile
PARAMS: email (string), password (string)
RETURN: isUniqueUser (bool)
*/
async function validateUniqueUser(email, password) {
// connect to database
const database = await client.connect().catch(err => {
log("ERROR while connecting to database at: validateUniqueUser");
console.log(err);
client.close();
});
// database connection failed
if (!database) {
return false;
}
// connection successful => find user
let user;
try {
user = await database.db("guitar-practice-suite").collection("users").findOne({email: email});
} catch(err) {
log("ERROR while finding user in database at: validateUniqueUser");
console.log(err);
client.close();
return false;
} finally {
client.close();
// user not found (unique)
if (user === null || user === undefined) {
return true;
}
return false;
}
}
Here is the function for inserting the user into the collections:
/* CREATE_PRACTICE_PROFILE
USE: insert a practice profile into the database
PARAMS: email (string), password (string)
RETURN: userCreated (bool)
*/
async function createPracticeProfile(email, password) {
// hash password
let hashedPassword;
try {
hashedPassword = await new Promise((resolve, reject) => {
bcrypt.hash(password, null, null, function(err, hash) {
if (err) {
reject(err);
}
resolve(hash)
});
});
} catch(err) {
log("ERROR while hashing password at: createPracticeProfile");
console.log(err);
return false;
}
// connect to database
const database = await client.connect().catch(err => {
log("ERROR while connecting to database at: validateUniqueUser");
console.log(err);
client.close();
});
// database connection failed
if (!database) {
return false;
}
// database connection successful => insert user into database
let insertUserToUsers;
let insertUserToExercises;
let insertUserToCustomExercises;
try {
insertUserToUsers = await database.db("guitar-practice-suite").collection("users").insertOne({email: email, password: hashedPassword});
insertUserToExercises = await database.db("guitar-practice-suite").collection("exercises").insertOne({email: email});
insertUserToCustomExercises = await database.db("guitar-practice-suite").collection("custom-exercises").insertOne({email: email, exercises: []});
} catch(err) {
log("ERROR while inserting user into database at: createPracticeProfile");
console.log(err);
client.close();
return false;
} finally {
client.close();
return insertUserToUsers && insertUserToExercises && insertUserToCustomExercises;
}
}
I've found the solution to the problem, but I'm not sure I understand the reasoning.
The client.close() in the finally block of the validateUniqueUser function. It was closing the connection before the connection in the createPracticeProfile function was finished inserting the user.
When that line is taken out, the function works.
The issue is client variable needs to be reinstantiated again,
const client = new MongoClient(uri, { useUnifiedTopology: true}, { useNewUrlParser: true }, { connectTimeoutMS: 30000 }, { keepAlive: 1});
Try putting this in start of createPracticeProfile, validateUniqueUser and other functions
I was getting the error
MongoError: Topology is closed
because of the authentication problem
MongoEror: Authentication failed
In my case, the problem was with the password of my database. My password only contained numerical digits.
I changed the password to all characters and both the errors were solved.
Configure your client connection like below example
var MongoClient = require('mongodb').MongoClient;
var Server = require('mongodb').Server;
var mongoClient = new MongoClient(new Server('localhost', 27017));
mongoClient.open(function(err, mongoClient) {
var db1 = mongoClient.db("mydb");
mongoClient.close();
});
In my case - connecting to AtlasDB using the MongoClient - I had to whitelist the IP i was accessing the cluster from
I think your mongodb service is stopped, to start it
Task Manager -> Services -> Mongodb -> RightClick -> Start
My code has been working fine for a long time and hasn't thrown this error before: MongoError: Topology is closed.
But due to the fact that my laptop was turned on for a long time and I was simultaneously developing other projects on it, while the main one was running in the terminal, mongo most likely did not close one of the connections to the database and opened another in parallel, creating some kind of collision.
In general, in my case, the usual restart of the computer helped and a similar error did not occur again.
I'm using the mongoose ODM for a project. My schema looks like this:
const applicantSchema = new Schema({
regno: {
type: String,
unique: true,
required: true
},
email: {
type: String,
unique: true,
required: true
}
});
const Applicant = mongoose.model('Applicant', applicantSchema);
I created a wrapper function to add a new document which looks like this:
function addApplicant(newApplicant, callback){
mongoose.connect(url);
const db = mongoose.connection;
console.log(newApplicant);
console.log(typeof newApplicant);
const applicant = new Applicant(newApplicant);
applicant.save((err) => {
if(err) return callback(err);
let info = "successfully saved target";
return callback(null, info);
});
}
I call this function within my route that handles the concerned post request.
router.post('/applicant/response', (req, res) => {
//process sent response here and add to DB
//console.log(req.body);
let newApplicant = {
regno: req.body.regno,
email: req.body.email
}
//console.log(newApplicant);
applicant.addApplicant(newApplicant, (err, info) => {
if(err){ console.log(err); res.end(err);}
res.end('complete, resp: ' + info);
});
});
However, mongoose gives me a validation error (path 'regno' is required) even though I am supplying a value for regno. This happens with all the fields marked as required.
If I remove the 'required: true' option the document is saved to the db as expected.
Any help will be appreciated. :)
It turns out that in this case, something was wrong with the way postman was sending data in a POST request. When I tested this later in postman using JSON as the data format (and ensuring that the Content-Type header is set to application/json), the code worked as expected.
To those facing a similar issue, check the headers postman sends with the request, and ensure that they are what you'd expect them to be.
In your express entry file where you expose your endpoints and setup express you should have app.use(express.json()); written above the endpoint.
const express = require("express");
require("./src/db/mongoose");
const User = require("./src/models/user");
const app = express();
const port = process.env.PORT || 3000;
// THIS LINE IS MANDATORY
app.use(express.json());
app.post("/users", async(req, res) => {
const user = new User(req.body);
try {
await user.status(201).save();
res.send(user);
} catch (error) {
res.status(400).send(error);
}
});
app.listen(port, () => {
console.log(`Server is runnung in port ${port}`);
});
var n = new Chat();
n.name = "chat room";
n.save(function(){
//console.log(THE OBJECT ID that I just saved);
});
I want to console.log the object id of the object I just saved. How do I do that in Mongoose?
This just worked for me:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/lol', function(err) {
if (err) { console.log(err) }
});
var ChatSchema = new Schema({
name: String
});
mongoose.model('Chat', ChatSchema);
var Chat = mongoose.model('Chat');
var n = new Chat();
n.name = "chat room";
n.save(function(err,room) {
console.log(room.id);
});
$ node test.js
4e3444818cde747f02000001
$
I'm on mongoose 1.7.2 and this works just fine, just ran it again to be sure.
Mongo sends the complete document as a callbackobject so you can simply get it from there only.
for example
n.save(function(err,room){
var newRoomId = room._id;
});
You can manually generate the _id then you don't have to worry about pulling it back out later.
var mongoose = require('mongoose');
var myId = mongoose.Types.ObjectId();
// then set it manually when you create your object
_id: myId
// then use the variable wherever
You can get the object id in Mongoose right after creating a new object instance without having to save it to the database.
I'm using this code work in mongoose 4. You can try it in other versions.
var n = new Chat();
var _id = n._id;
or
n.save((function (_id) {
return function () {
console.log(_id);
// your save callback code in here
};
})(n._id));
Other answers have mentioned adding a callback, I prefer to use .then()
n.name = "chat room";
n.save()
.then(chatRoom => console.log(chatRoom._id));
example from the docs:.
var gnr = new Band({
name: "Guns N' Roses",
members: ['Axl', 'Slash']
});
var promise = gnr.save();
assert.ok(promise instanceof Promise);
promise.then(function (doc) {
assert.equal(doc.name, "Guns N' Roses");
});
Well, I have this:
TryThisSchema.post("save", function(next) {
console.log(this._id);
});
Notice the "post" in the first line. With my version of Mongoose, I have no trouble getting the _id value after the data is saved.
With save all you just need to do is:
n.save((err, room) => {
if (err) return `Error occurred while saving ${err}`;
const { _id } = room;
console.log(`New room id: ${_id}`);
return room;
});
Just in case someone is wondering how to get the same result using create:
const array = [{ type: 'jelly bean' }, { type: 'snickers' }];
Candy.create(array, (err, candies) => {
if (err) // ...
const [jellybean, snickers] = candies;
const jellybeadId = jellybean._id;
const snickersId = snickers._id;
// ...
});
Check out the official doc
Actually the ID should already be there when instantiating the object
var n = new Chat();
console.log(n._id) // => 4e7819d26f29f407b0... -> ID is already allocated
Check this answer here: https://stackoverflow.com/a/7480248/318380
As per Mongoose v5.x documentation:
The save() method returns a promise. If save() succeeds, the
promise resolves to the document that was saved.
Using that, something like this will also work:
let id;
n.save().then(savedDoc => {
id = savedDoc.id;
});
using async function
router.post('/create-new-chat', async (req, res) => {
const chat = new Chat({ name : 'chat room' });
try {
await chat.save();
console.log(chat._id);
}catch (e) {
console.log(e)
}
});