db.collection is not a function when using MongoClient v3.0
Asked Answered
P

13

166

I have been trying W3schools tutorial on nodeJS with MongoDB.

When I try to implement this example in a nodeJS environment and invoke the function with an AJAX call, I got the error below:

TypeError: db.collection is not a function
    at c:\Users\user\Desktop\Web Project\WebService.JS:79:14
    at args.push (c:\Users\user\node_modules\mongodb\lib\utils.js:431:72)
    at c:\Users\user\node_modules\mongodb\lib\mongo_client.js:254:5
    at connectCallback (c:\Users\user\node_modules\mongodb\lib\mongo_client.js:933:5)
    at c:\Users\user\node_modules\mongodb\lib\mongo_client.js:794:11
    at _combinedTickCallback (internal/process/next_tick.js:73:7)
    at process._tickCallback (internal/process/next_tick.js:104:9)

Please find below my implemented code:

var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/mytestingdb";

MongoClient.connect(url, function(err, db) {
  if (err) throw err;
  db.collection("customers").findOne({}, function(err, result) {
    if (err) throw err;
    console.log(result.name);
    db.close();
  });
});

Note that the error occurs whenever the execution hits:

db.collection("customers").findOne({}, function(err, result) {}

Also, note (in case it matters) that I have installed the latest MongoDB package for node JS (npm install mongodb), and the MongoDB version is MongoDB Enterprise 3.4.4, with MongoDB Node.js driver v3.0.0-rc0.

Pollinate answered 5/12, 2017 at 20:34 Comment(11)
Did you make sure: (1) the database is running (given there was no error, I guess so); (2) the database mytestingdb exists (try using robomongo/robo3t to access your connection and see the collections) (3) The collection customers actually exists; Also tell us how you are calling that script and what version of Nodejs (how did you install?)Karlie
The database and the collection exist (I have accessed them using Studio 3t). I am debugging nodeJS by calling the method through an AJAX call, basically the breakpoints are being hit and everything works fine until I get the exception stated above. NodeJS version is v6.11.4Pollinate
Then replace the code that starts with db.collection()... with a console log to see if it gets there, no problem.Karlie
The database and the collection exist (I have accessed them using Studio 3t). I am debugging nodeJS by calling the method through an AJAX call, basically the breakpoints are being hit and everything works fine until I get the exception stated above. NodeJS version is v6.11.4Pollinate
Possible duplicate of #43779823 #34827897Karlie
Please specify the npm package mongodb version. That is in your package.json and IS NOT your mongo server version. According to the docs, your code should be okay mongodb.github.io/node-mongodb-native/2.2/tutorials/crudKarlie
Could you add console.log(db) before db.collection or even more detailed log to see what is inside db?Coldiron
I have accessed the package file within the mongodb node modules, "version": "3.0.0-rc0"Pollinate
So i should download and install the newest mongodb version and retryPollinate
Downgrade MongoDB database or node modules mongodb packages?Pollinate
Kindly consider upvoting AyoO for his solutionPollinate
W
81

I encountered the same thing. In package.json, change mongodb line to "mongodb": "^2.2.33". You will need to uninstall mongodb npm by removing MongoDB Driver/ node_modules or etc , then install npm to install this version.

This resolved the issue for me. Seems to be a bug or docs need to be updated.

Widescreen answered 5/12, 2017 at 21:17 Comment(7)
check MikaS' answerReligieux
downgrading to an earlier version isn't really a solution it just means you didn't bother looking into the API changes that caused thisFoothill
@JohnCulviner - This was a timing issue; not a laziness issue. This issue occurred while they were in the process of releasing the new update. I (and the original poster) obviously did not realize this. At that time, the docs were not yet updated. They were updated shortly after. Anyone looking to resolve this as of now should follow MikaS's comment and review the updated docs.. I did the same after the docs were updated and was able to continue with the upgraded version.Widescreen
Coming across this now - I was running into this issue and had the "mongodb:" "3.0.2" installed in package.json, are there issues with the new version?Mayworm
Does not help at all. Why it is flagged as the correct answer?Lebrun
It should not be the solution. Its kind of work around. Answer written by @MikaS is absolutely perfect worked for me.Iolanthe
please follow the @Dre Jackson ans. 2nd ans. This is a wrong approach.Sidewalk
C
541

For people on version 3.0 of the MongoDB native NodeJS driver:

(This is applicable to people with "mongodb": "^3.0.0-rc0", or a later version in package.json, that want to keep using the latest version.)

In version 2.x of the MongoDB native NodeJS driver you would get the database object as an argument to the connect callback:

MongoClient.connect('mongodb://localhost:27017/mytestingdb', (err, db) => {
  // Database returned
});

According to the changelog for 3.0 you now get a client object containing the database object instead:

MongoClient.connect('mongodb://localhost:27017', (err, client) => {
  // Client returned
  var db = client.db('mytestingdb');
});

The close() method has also been moved to the client. The code in the question can therefore be translated to:

MongoClient.connect('mongodb://localhost', function (err, client) {
  if (err) throw err;

  var db = client.db('mytestingdb');

  db.collection('customers').findOne({}, function (findErr, result) {
    if (findErr) throw findErr;
    console.log(result.name);
    client.close();
  });
}); 
Courson answered 5/12, 2017 at 21:30 Comment(7)
Now do we have to write this (var db = client.db('mytestingdb');) extra line each time instead of just writing like this (MongoClient.connect('mongodb://localhost:27017/mytestingdb'))? I'm always working with the same database. Is there any approach to eliminate that extra line? It's kinda like time-consuming thing for me.Manchineel
@Manchineel Sounds to me like you are connecting to the db for every request. That's considered a bad idea. You can read about it here. If you only connect once there is only one new line per app you create.Courson
@MikaS Oh yes. I was connecting to the db like you said. I didn't know that we can connect once and reuse the db variable. Thank you so much.Manchineel
Great answer; figuring this out was a time suck, I should remember to RTFMHeavyset
I did implement the client like so, but there are still the same problems (db.collection is not a function) inside \node_modules\mongodb\lib\gridfs-stream\index.js:50:27Festive
In a serverless environment where DB is passed to the app dynamically as a URI it is additional work to parse the URI to extract the DB name. Does mongodb now ignore the DB name from the URI? Or is there a way to get a client.db handle without parsing the URI manually?Ann
For connection pooling, will queries and update on collection level or database level objects work (like collection.insertOne) ? Or do we need to perform updates and queries using the connection object (like conn.db('mydb').collection('user').insertOne) for the connection pooling to work?Chiropodist
W
81

I encountered the same thing. In package.json, change mongodb line to "mongodb": "^2.2.33". You will need to uninstall mongodb npm by removing MongoDB Driver/ node_modules or etc , then install npm to install this version.

This resolved the issue for me. Seems to be a bug or docs need to be updated.

Widescreen answered 5/12, 2017 at 21:17 Comment(7)
check MikaS' answerReligieux
downgrading to an earlier version isn't really a solution it just means you didn't bother looking into the API changes that caused thisFoothill
@JohnCulviner - This was a timing issue; not a laziness issue. This issue occurred while they were in the process of releasing the new update. I (and the original poster) obviously did not realize this. At that time, the docs were not yet updated. They were updated shortly after. Anyone looking to resolve this as of now should follow MikaS's comment and review the updated docs.. I did the same after the docs were updated and was able to continue with the upgraded version.Widescreen
Coming across this now - I was running into this issue and had the "mongodb:" "3.0.2" installed in package.json, are there issues with the new version?Mayworm
Does not help at all. Why it is flagged as the correct answer?Lebrun
It should not be the solution. Its kind of work around. Answer written by @MikaS is absolutely perfect worked for me.Iolanthe
please follow the @Dre Jackson ans. 2nd ans. This is a wrong approach.Sidewalk
L
43

For those that want to continue using version ^3.0.1 be aware of the changes to how you use the MongoClient.connect() method. The callback doesn't return db instead it returns client, against which there is a function called db(dbname) that you must invoke to get the db instance you are looking for.

const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');

// Connection URL
const url = 'mongodb://localhost:27017';

// Database Name
const dbName = 'myproject';

// Use connect method to connect to the server
MongoClient.connect(url, function(err, client) {
  assert.equal(null, err);
  console.log("Connected successfully to server");

  const db = client.db(dbName);

  client.close();
});
Lenitalenitive answered 26/12, 2017 at 5:1 Comment(2)
This answer is more recent and applies to version 3 of the driver. ThanksEtzel
I recommend this solution, it is more appropriate for future reference.Jardiniere
F
39
MongoClient.connect(url (err, client) => {
    if(err) throw err;

    let database = client.db('databaseName');

    database.collection('name').find()
    .toArray((err, results) => {
        if(err) throw err;

        results.forEach((value)=>{
            console.log(value.name);
        });
    })
})

The only problem with your code is that you are accessing the object that's holding the database handler. You must access the database directly (see database variable above). This code will return your database in an array and then it loops through it and logs the name for everyone in the database.

Frangipane answered 9/6, 2018 at 13:11 Comment(5)
This answer is marked as low quality because of its length and content. Please provide more information.Remus
It's only as long as it needs to be. This answer helped me.Cherise
@ManuelHernandez glad it helped :)Frangipane
this is the correct ans. Please mark this as a correct ans.Sidewalk
Look at this answer to see a loop over the documents in a collection.Mistaken
B
14

Piggy backing on @MikkaS answer for Mongo Client v3.x, I just needed the async / await format, which looks slightly modified as this:

const myFunc = async () => {

     // Prepping here...


    // Connect
    let client = await MongoClient.connect('mongodb://localhost');
    let db = await client.db();

    // Run the query
    let cursor = await db.collection('customers').find({});

    // Do whatever you want on the result.
}
Beating answered 14/3, 2018 at 21:4 Comment(0)
O
11

I did a little experimenting to see if I could keep the database name as part of the url. I prefer the promise syntax but it should still work for the callback syntax. Notice below that client.db() is called without passing any parameters.

MongoClient.connect(
    'mongodb://localhost:27017/mytestingdb', 
    { useNewUrlParser: true}
)
.then(client => {

    // The database name is part of the url.  client.db() seems 
    // to know that and works even without a parameter that 
    // relays the db name.
    let db = client.db(); 

    console.log('the current database is: ' + db.s.databaseName);
    // client.close() if you want to

})
.catch(err => console.log(err));

My package.json lists monbodb ^3.2.5.

The 'useNewUrlParser' option is not required if you're willing to deal with a deprecation warning. But it is wise to use at this point until version 4 comes out where presumably the new driver will be the default and you won't need the option anymore.

Oaf answered 7/6, 2019 at 18:1 Comment(0)
C
7

It used to work with the older versions of MongoDb client ~ 2.2.33

Option 1: So you can either use the older version

npm uninstall mongodb --save

npm install [email protected] --save

Option 2: Keep using the newer version (3.0 and above) and modify the code a little bit.

let MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017', function(err, client){
  if(err) throw err;
  let db = client.db('myTestingDb');
  db.collection('customers').find().toArray(function(err, result){
    if(err) throw err;
    console.log(result);
    client.close();
    });
 });
Crockery answered 2/9, 2020 at 8:28 Comment(0)
I
5

I solved it easily via running these codes:

 npm uninstall mongodb --save

 npm install [email protected] --save

Happy Coding!

Ionopause answered 8/2, 2018 at 18:9 Comment(0)
P
5

If someone is still trying how to resolve this error, I have done this like below.

const MongoClient = require('mongodb').MongoClient;
// Connection URL
const url = 'mongodb://localhost:27017';
// Database Name
const dbName = 'mytestingdb';

const retrieveCustomers = (db, callback)=>{
    // Get the customers collection
    const collection = db.collection('customers');
    // Find some customers
    collection.find({}).toArray((err, customers) =>{
        if(err) throw err;
      console.log("Found the following records");
      console.log(customers)
      callback(customers);
    });
}

const retrieveCustomer = (db, callback)=>{
    // Get the customers collection
    const collection = db.collection('customers');
    // Find some customers
    collection.find({'name': 'mahendra'}).toArray((err, customers) =>{
        if(err) throw err;
      console.log("Found the following records");
      console.log(customers)
      callback(customers);
    });
}

const insertCustomers = (db, callback)=> {
    // Get the customers collection
    const collection = db.collection('customers');
    const dataArray = [{name : 'mahendra'}, {name :'divit'}, {name : 'aryan'} ];
    // Insert some customers
    collection.insertMany(dataArray, (err, result)=> {
        if(err) throw err;
        console.log("Inserted 3 customers into the collection");
        callback(result);
    });
}

// Use connect method to connect to the server
MongoClient.connect(url,{ useUnifiedTopology: true }, (err, client) => {
  console.log("Connected successfully to server");
  const db = client.db(dbName);
  insertCustomers(db, ()=> {
    retrieveCustomers(db, ()=> {
        retrieveCustomer(db, ()=> {
            client.close();
        });
    });
  });
});
Petulancy answered 18/5, 2020 at 6:50 Comment(1)
This solution and @Dre Jackson one's are the ones that work with node as of 07/2020. Seems like what is passed as an argument to the connect callback is the MongoClient rather than a db, which is why you need to fetch the db from it. Other than that, this solution also lists the useUnifiedTopology: true, which is also needed nowodays.Mccurdy
B
4

I have MongoDB shell version v3.6.4, below code use mongoclient, It's good for me:

var MongoClient = require('mongodb').MongoClient,
assert = require('assert');
var url = 'mongodb://localhost:27017/video';
MongoClient.connect(url,{ useNewUrlParser: true }, function(err, client) 
{
assert.equal(null, err);
console.log("Successfully connected to server");
var db = client.db('video');
// Find some documents in our collection
db.collection('movies').find({}).toArray(function(err, docs) {
// Print the documents returned
docs.forEach(function(doc) {
console.log(doc.title);
});
// Close the DB
client.close();
});
// Declare success
console.log("Called find()");
 });
Biannulate answered 2/6, 2018 at 8:1 Comment(1)
This question relates to the node driver, not the shell.Kolomna
S
1

MongoDB queries return a cursor to an array stored in memory. To access that array's result you must call .toArray() at the end of the query.

  db.collection("customers").find({}).toArray() 
Semiyearly answered 24/5, 2019 at 16:46 Comment(0)
K
0

Late answer but maybe someone will need it in future

we can create async function which one will return our collection and db instances

const dBInstances = async () => {
  const collection = await db
    .then((client) => {
      const db = client.db();
      const collection = db.collection("AGGREGATION");
      return { collection: collection, db: db };
    })
    .catch((err) => {
      console.log(`Data base instances error ${err}`);
    });

  return collection;
};

and after we can use result of execution dBInstances() by this way i used JS destructurisation in example below

const test = async (req, res) => {
  const { collection, db } = await dBInstances();
  console.log(collection);
  console.log(db);
};

now we have separated access to our db and collection.

Kristy answered 2/6, 2021 at 10:48 Comment(0)
V
0

Recently I had the same issue, I finally resolved it using MongoDB official website documentation and sample codes.

My MongoDB client version is "mongodb": "^4.4.1" and I managed to insert a document finally without needing to downgrade my MongoDB package according to the approved answer which seems to be obsolete.

import { MongoClient } from "mongodb";

// Replace the uri string with your MongoDB deployment's connection string.
const uri = "<connection string uri>";

const client = new MongoClient(uri);

async function run() {
  try {
    await client.connect();

    const database = client.db("insertDB");
    const haiku = database.collection("haiku");
    // create a document to insert
    const doc = {
      title: "Record of a Shriveled Datum",
      content: "No bytes, no problem. Just insert a document, in MongoDB",
    }
    const result = await haiku.insertOne(doc);

    console.log(`A document was inserted with the _id: ${result.insertedId}`);
  } finally {
    await client.close();
  }
}
run().catch(console.dir);
Verbosity answered 24/3, 2022 at 11:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.