MongoDB Quick Start fails, keeps returning "null" on Terminal - node.js

Hi, I am self-learning MongoDB (with Node.js). Totally new to programming.
My first Node.js application doesn't return the MongoDB document like it supposed to.
What I want to achieve:
To work with the native MongoDB driver, and to complete the quick start procedure on MongoDB website: https://www.mongodb.com/docs/drivers/node/current/quick-start/
What I have tried so far:
Installed node & npm correctly;
Installed MongoDB#4.8 correctly;
Initialized all these via Terminal;
Set up Atlas, obtained connection string.
Still, when I put template (obtained from MongoDB quick start tutorial) into my server.js file, entered "npx nodemon app.js" to test, it returns: "null".
Here's code I put into server.js: (all account & password typed in correctly)
const { MongoClient } = require("mongodb");
// const uri = "mongodb://localhost:27017";
const uri = "mongodb+srv://<myClusterUsername>:<myPassword>#cluster0.fytvkcs.mongodb.net/?retryWrites=true&w=majority";
const client = new MongoClient(uri);
async function run() {
try {
const database = client.db('sample_mflix');
const movies = database.collection('movies');
// Query for a movie that has the title 'Back to the Future'
const query = { title: 'Back to the Future' };
const movie = await movies.findOne(query);
console.log(movie);
} finally {
// Ensures that the client will close when you finish/error
await client.close();
}
}
run().catch(console.dir);
As you can see, I also tried uri: localhost:27017, but output stay still on my Terminal: "null".
According to MongoDB, it was supposed to return such online sample doc:
{
_id: ...,
plot: 'A young man is accidentally sent 30 years into the past...',
genres: [ 'Adventure', 'Comedy', 'Sci-Fi' ],
...
title: 'Back to the Future',
...
}
Your help would be appreciated! Thanks very much!

you should open the folder in visual studio code like this :
enter image description here

Related

keep fetching data up to date

I have just a question I want to ask if anybody have an idea about it.
I'm building a full stack application backed by nodejs and using typescript for it, in my nodejs app I'm making a fetch for an API that later on I will serve it to the user but I have one small issue, I'm using node-fetch for now but the data which are fetched are changing all the time eg. now I have 10 entries, after 5 seconds I have 30 entries, so is there a way or mechanism to make my fetching to the data with nodejs up to date by fetching them in the background?
Thanks in advance!
Easiest solution to implement and good in actual sense for making your web app realtime https://pusher.com/
This is how you can handle pusher within your NodeJS App
import Pusher from 'pusher'
//Below are the keys that you will get from pusher when you go to getting started
// within your Dashboard
const pusher = new Pusher({
appId: "<Your app id provided by pusher>",
key: "<Key id provided by pusher>",
secret: "<Secret key given by pusher>",
cluster: "<cluster given by pusher",
useTLS: true
});
Now you want to setup a changeStream for your Collection in MongoDB
const db = mongoose.collection;
db.once('open', ()=>{
const postCollection = db.collection('posts')//This will be dependent on the collection you want to watch
const changeStream = postCollection.watch()//Make sure the collection name above are acurate
changeStream.on('change', (change)=>{
const post = change.fullDocument;//Change bring back content that change in DB Collection
if (change.operationType === 'insert'){
pusher.triger('<write channel for your pusher>', '<event in this case inser>', {
newPost:post
})
}
})
})
By that setup your pusher and backend is working now is time to setup frontend
If your usin VanillaJS the Pusher getting started has code for you
If your using ReactJS here's is the code below
import Pusher from 'pusher-js'
useEffect(()=>{
Pusher.logToConsole = true;
var pusher = new Pusher('<Key received from pusher>', {
cluster: '<cluster received from pusher>'
});
var channel = pusher.subscribe('<channel name that you wrote in server');
channel.bind('<event that you wrote in sever',(data)=> {
alert(JSON.stringify(data)); // This will be the data entries coming as soon as they enter DB then you can update your state by using spread operators to maintain what you have and also add new contents
});
//Very important to have a clean-up function to render this once
return ()=>{
pusher.unbind();
pusher.unsubscribe_all();
}
})
Now like this you have everything being realtime

How can I verify I don't need the mLab add-on for my Heroku node.js app?

After reading through the mLab -> Atlas migration plan a few times, I decided I'd try a different way. My coding background is mainly asm on mcs51 so I'm something of a n00b in the node.js/mongo/heroku world. I barely understood half of the migration process.
So I wrote a small test app following this blog entry and then used what I'd learned to modify my actual app to talk to Atlas directly. I exported the collections from the old db to JSON, then imported them into the Atlas version to recreate the database. Everything appears to be working correctly; I don't see any data going into the old db and it looks like the new Atlas db is getting all the action.
But I'm leery of deleting the mLab add-on from Heroku until I've verified that it's truly not needed any more, because I'm pretty sure that I won't be able to recreate it if it turns out I've missed something.
So my question is, how can I ensure I'm no longer using the mLab add-on? I don't really understand what it was doing for me in the first place so I'm not sure how to verify I'm not using it any more.
Here are the relevant code snippets I'm using to access the Atlas db...
function myEncode(str) { // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
return encodeURIComponent(str).replace(/[!'()*]/g, function(c) {
return '%' + c.charCodeAt(0).toString(16);
});
}
const ATLASURI = process.env.ATLASURI;
const ATLASDB = process.env.ATLASDB;
const ATLASUSER = process.env.ATLASUSER;
const ATLASPW = myEncode(process.env.ATLASPW); // wrapper needed to handle strong paswords...
const dbURL = "mongodb+srv://"+ATLASUSER+":"+ATLASPW+"#"+ATLASURI+"/"+ATLASDB+"?retryWrites=true&w=majority";
var GoogleStrategy = require('passport-google-oauth20').Strategy;
const {MongoClient} = require('mongodb');
const client = new MongoClient(dbURL, { useNewUrlParser: true, useUnifiedTopology: true });
var store = new MongoDBStore({uri: dbURL,collection: 'Sessions'});
var db = undefined;
client.connect(async function(err) {
if(err) {console.log("Error:\n"+String(err));}
db = await client.db(ATLASDB);
console.log("Connected to db!");
banner();
});

MongoDB (Mongoose) `findByIdAndDelete` not deleting (testing with Postman)

I've got my Mongoose code in a separate model.js file, while Express code for handling http requests is in app.js. I'm just practising creating APIs and testing them on Postman, for an imaginary wiki article site. The api I'm struggling to get it to work is deleting one article. (Note: for the sake of brevity, I've only included the code in question, i.e. app.delete('/articles/:id' .... from app.js, and the static method it calls from model.js - deleteOneArticleFromDB(articleID)
app.js:
const express = require('express');
const bodyParser = require('body-parser');
const model = require('./model');
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.delete('/articles/:id', async (req, res) => {
const articleID = req.params.id;
console.log(`req.params.id: ${req.params.id}`);
try {
const response = await model.DBUtility.deleteOneArticleFromDB(articleID);
res.status(200).json({message: response, app: 'wiki-api'});
} catch (err) {
res.json({message: err, app: 'wiki-api'});
}
});
const port = 3000;
app.listen(port, () => {
console.log(`Server started on port ${port}`);
});
model.js:
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/wikiDB', {useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false });
const articleSchema = new mongoose.Schema({
title: String,
content: String
});
const Article = mongoose.model('Article', articleSchema);
class DBUtility {
static deleteOneArticleFromDB(articleID) {
return new Promise((resolve, reject) => {
Article.findByIdAndDelete(articleID, (err) => {
if (err) {
reject(err);
} else {
resolve(`Deleted article ${articleID} successfully`);
}
});
});
}
}
exports.DBUtility = DBUtility;
I have 5 articles (5 documents) in my Database:
{
"_id" : "5c139771d79ac8eac11e754a",
"title" : "API",
"content" : "API stands for Application Programming Interface. It is a set of subroutine definitions, communication protocols, and tools for building software. In general terms, it is a set of clearly defined methods of communication among various components. A good API makes it easier to develop a computer program by providing all the building blocks, which are then put together by the programmer."
}
/* 2 */
{
"_id" : "5c1398aad79ac8eac11e7561",
"title" : "Bootstrap",
"content" : "This is a framework developed by Twitter that contains pre-made front-end templates for web design"
}
/* 3 */
{
"_id" : "5c1398ecd79ac8eac11e7567",
"title" : "DOM",
"content" : "The Document Object Model is like an API for interacting with our HTML"
}
/* 4 */
{
"_id" : "5ea2c188fa57aa1b6453eda5",
"title" : "Node JS",
"content" : "Node.js is an open-source, cross-platform, JavaScript runtime environment that executes JavaScript code outside of a web browser. Node.js lets developers use JavaScript to write command line tools and for server-side scripting—running scripts server-side to produce dynamic web page content before the page is sent to the user's web browser. Consequently, Node.js represents a \"JavaScript everywhere\" paradigm,[6] unifying web-application development around a single programming language, rather than different languages for server- and client-side scripts.",
"__v" : 0
}
/* 5 */
{
"_id" : "5ea2d5304e19b11e0013a86a",
"title" : "EJS",
"content" : "EJS is a simple templating language that lets you generate HTML markup with plain JavaScript. No religiousness about how to organize things. No reinvention of iteration and control-flow. It's just plain JavaScript",
"__v" : 0
}
I'm trying to delete the last article (document) with title EJS. So in Postman I run the http request as follows:
As you can see, I get a success response. However, when I check my database, the document is still there (I have clicked refresh several times and also tested it with a GET request to return all articles, which showed the article is still there):
Here's the terminal output:
[nodemon] starting `node app.js`
Server started on port 3000
req.params.id: 5ea2d5304e19b11e0013a86a
I've been on this for two days. I've checked all previous SO posts with similar titles to mine, but I couldn't see one that applies to my issue. I don't understand where I'm going wrong!! Any help would be really appreciated.
UPDATE
As per the solution below by Mohammed Yousry, I realised that I added the _id field manually using strings, as I was following along to a tutorial. Hence not allowing MongoDB to create the _id field instead, as an ObjectId. Therefore, my _id field was of type String rather than ObjectId. So to resolve this, I deleted all documents from the database and re-added them, using POSTMAN with the POST method I created - for creating/adding a new article document to the database, providing only the title and content fields in the request body. Hence allowing MongoDB to create the _id field instead, for each article document. Now in the database the _id field is of type ObjectId. This still hasn't resolved my issue fully, but it's one step further. Still working on reaching a solution. Please refer to the discussions below in the solution section.
1- may be your mongoose version does not support findByIdAndDelete
try findByIdAndRemove instead
2- you can pass the id to that method as a string or as an objectId
make sure you are passing the right id without any spaces
const articleID = req.params.id.toString().trim(); // trim will remove any spaces before or after the id
Update
according to this image
it seems you have inserted your data manually, and these data contained the _id as a string, as the type of the _id is a string here as you can see in this image
I suggest you to let MongoDB to set the _id itself
If you could change the _id type to be ObjectId
or If you can't change the type of _id, you can take a backup of your articles, then remove all those articles manually and add them again without the _id, let mongoDB set that _id, and try your code again
hope this may solve the issue
Update 2
After checking the codes in github, I know the reason why you got this strange behavior
1- you have a route app.route('/articles/:articleTitle') defined before the route app.delete('/articles/:id'
so when you are trying to delete some article by passing the id, nodeJS an express will pass it to the first matching route, as it does not know the params you send, it's searching for the base url in the route, so it deals with the first route which matching the url : '/articles/something', take that something as the article title
then call the deleteOneArticleByTitleFromDB method
MongoDB is then searching for some article with title = the id you passed, it found nothing, then, it doesn't remove any article
2- I suggest you not to define some routes with the same base url
so you can define the delete by Id route like the following
app.delete('/arti/cles/:id', async (req, res) => // note the slash inside articles word
or anything you want except the current one
by this you avoid this contradiction between the routes
In MongoDB, the _id property is of type ObjectId.
I had the same problem and fixed it by passing over an ObjectId instead.
Have you tried the following ?
const Mongoose = require('mongoose');
const articleId = Mongoose.Types.ObjectId(req.params.id);
#Hazzaldo I was facing the same problem. But apparently, I didn't write await before findByIdAndDelete(). After writing await before it fixed it for me.
I saw your code, as you are wrapping the findByIdAndDelete inside a promise which in itself is a promise, I would recommend you to try to await the findByIdAndDelete first and then return the promise.

can't find mongodb collections/data

I'm working on a web app with node/express/mongodb, using mongoose. I created a folder in my project called data and inside I created another folder called db
data
db
when I start mongo, I use the --dbpath parameter and point it to my project data folder that I created. It connects fine and everything. I've been writing some data to the database, and the application loads it correctly, but I can't find the data when I open mongo shell.
first thing is, when I open shell the only database I get is test. Is this auto created if I don't specify a database name? how do I specify a database name? I have the following in my app.js file:
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/abduldb');
My guess is that a database named abduldb should be created correct? I don't see this in mongo shell.
Also, when using the test database, I run show collections and it shows no results... Where exactly is my data being written? I only have 1 model right now and it looks like this:
var mongoose = require('mongoose');
var ItemSchema = new mongoose.Schema({
title: String,
body: String
});
mongoose.model('item', ItemSchema);
and I'm adding new items in my route file using:
router.post('/items', function (req, res, next) {
var item = new Item(req.body);
item.save(function(err, item){
if(err){ return next(err); }
res.json(item);
});
});
When you are in the mongo shell, try this command: "use abduldb".
The reason you don't see your collections is because you are automatically connected to the test db. If you want to change that, run this when you start mongo shell:
mongo abduldb
Alternatively, you can change the default db in your .mongorc.js file by adding/changing this line:
db = db.getSiblingDB("abduldb")
The .mongorc.js file can be found at /etc/mongorc.js, but is overridden if it exists in your home directory (i.e. /home/abduldb/.mongorc.js).

property model of object mongoose is not a function

I'm using Mongoosejs, with MongoDB and Node.js.
I followed some online tutorials and created myself a test app as below, but keep getting the error message "propert model of object mongoose is not a function.
I dont understand what this means and why its erroring since i followed the online tutorials near enough the same.
Here is my code
// MongoDB test app. Getting to know MongoDB via MongooseJS
var mongoose = require ('mongoose'),
Schema = mongoose.Schema;
//Create Schema
var Storydb = new Schema ({
title: String,
body: String,
date: Date
});
mongoose.connect('mongodb://localhost/test');
//setup model and pass it schema
mongoose.model = ('Storydb',Storydb);
var StoryModel = mongoose.model ('Storydb');
var story = new StoryModel();
//Insert Data
story.title = 'The Man in the green shirt';
story.body = 'once upon a time, way back';
story.date = Date.now();
//save
story.save(function(err){
if (err) {throw err; }
console.log('saved story');
mongoose.disconnect();
});`
I've already tested my MongoDB connection. No issues there, and i am able to insert and retrieve data via the Mongo CLI.
I have also tested my Node.js configuration with basic Hello World examples, and no issues with configuration.
Instead of:
//setup model and pass it schema
mongoose.model = ('Storydb',Storydb);
you should do:
//setup model and pass it schema
mongoose.model('Storydb',Storydb);

Resources