Categories
MongoDB Node.js Basics

Node.js Basics — MongoDB Collation and Queries

Node.js is a popular runtime platform to create programs that run on it.

It lets us run JavaScript outside the browser.

In this article, we’ll look at how to start using Node.js to create programs.

Collation Priority

If there are collation rules applied on the index and the query, then we can set the priority of the collation rule.

For example, we can write:

const { MongoClient } = require('mongodb');
const connection = "mongodb://localhost:27017";
const client = new MongoClient(connection);

async function run() {
  try {
    await client.connect();
    const db = client.db("test");
    await db.dropCollection('test');
    await db.createCollection("test");
    const testCollection = await db.collection('test');
    await testCollection.createIndex(
      { 'name': 1 },
      { 'collation': { 'locale': 'en' } });
    await testCollection.dropIndexes();
    await testCollection.deleteMany({})
    const result = await testCollection.insertMany([
      { "_id": 1, "name": "apples", "qty": 5, "rating": 3 },
      { "_id": 2, "name": "bananas", "qty": 7, "rating": 1 },
      { "_id": 3, "name": "oranges", "qty": 6, "rating": 2 },
      { "_id": 4, "name": "avocados", "qty": 3, "rating": 5 },
    ]);
    console.log(result)
    const options = { "collation": { "locale": "en_US", "strength": 2 } };
    const cursor = testCollection
      .find({}, options)
      .sort({ "name": -1 });
    cursor.forEach(console.dir);
  } finally {
    await client.close();
  }
}
run().catch(console.dir);

We have an options object to set the collation rule with the strength property.

The strength property determines the order of the collation rules we apply.

Collation Query

Collation is supported by find and sort queries.

For example, we can write:

const { MongoClient } = require('mongodb');
const connection = "mongodb://localhost:27017";
const client = new MongoClient(connection);

async function run() {
  try {
    await client.connect();
    const db = client.db("test");
    await db.dropCollection('test');
    await db.createCollection("test");
    const testCollection = await db.collection('test');
    await testCollection.createIndex(
      { 'name': 1 },
      { 'collation': { 'locale': 'en' } });
    await testCollection.dropIndexes();
    await testCollection.deleteMany({})
    const result = await testCollection.insertMany([
      { "_id": 1, "name": "apples", "qty": 5, "rating": 3 },
      { "_id": 2, "name": "bananas", "qty": 7, "rating": 1 },
      { "_id": 3, "name": "oranges", "qty": 6, "rating": 2 },
      { "_id": 4, "name": "avocados", "qty": 3, "rating": 5 },
    ]);
    console.log(result)
    const cursor = testCollection
      .find({ name: "name" }, { collation: { locale: "en" } })
      .sort({ name: 1 });
    cursor.forEach(console.dir);
  } finally {
    await client.close();
  }
}
run().catch(console.dir);

The 2nd argument of find has an object with the collation property to set the collation rules.

We can also set the collation rule with the findOneAndUpdate method:

const { MongoClient } = require('mongodb');
const connection = "mongodb://localhost:27017";
const client = new MongoClient(connection);

async function run() {
  try {
    await client.connect();
    const db = client.db("test");
    await db.dropCollection('test');
    await db.createCollection("test");
    const testCollection = await db.collection('test');
    await testCollection.createIndex(
      { 'name': 1 },
      { 'collation': { 'locale': 'en' } });
    await testCollection.dropIndexes();
    await testCollection.deleteMany({})
    const result = await testCollection.insertMany([
      { "_id": 1, "name": "apples", "qty": 5, "rating": 3 },
      { "_id": 2, "name": "bananas", "qty": 7, "rating": 1 },
      { "_id": 3, "name": "oranges", "qty": 6, "rating": 2 },
      { "_id": 4, "name": "avocados", "qty": 3, "rating": 5 },
    ]);
    console.log(result)
    testCollection
      .findOneAndUpdate(
        { qty: { $lt: 5 } },
        { $set: { rating: 5 } },
        { collation: { locale: "en" } },
      )
  } finally {
    await client.close();
  }
}
run().catch(console.dir);

The 3rd argument has the collation property set to set the collation rule.

Conclusion

The collation rule priority can be set when we make queries. Also, we can set collation rules when we find, sort or update items.

Categories
MongoDB Node.js Basics

Node.js Basics — Logging with MongoDB

Node.js is a popular runtime platform to create programs that run on it.

It lets us run JavaScript outside the browser.

In this article, we’ll look at how to start using Node.js to create programs.

Logging

The MongoDB Node.js client has a logger built into it.

To use it, we can write:

const { MongoClient, Logger } = require('mongodb');
const connection = "mongodb://localhost:27017";
const client = new MongoClient(connection);

async function run() {
  try {
    Logger.setLevel("debug");
    await client.connect();
    const db = client.db("test");
    db.dropCollection('test');
    db.createCollection('test');
    const testCollection = await db.collection('test');
    const result = await testCollection.insertMany([
      { "_id": 1, "name": "apples", "qty": 5, "rating": 3 },
      { "_id": 2, "name": "apples", "qty": 7, "rating": 1 },
      { "_id": 3, "name": "oranges", "qty": 6, "rating": 2 },
      { "_id": 4, "name": "avocados", "qty": 3, "rating": 5 },
    ]);
    console.log(result)
    const cursor = await testCollection.find();
    cursor.forEach(console.dir);
  } finally {
    await client.close();
  }
}
run().catch(console.dir);

to call Logger.setLevel to 'debug' to see all the debug messages when the methods below it are run.

We should see a lot more messages displayed in the console that without the logger.

Filter on a Specific Class

We can filter items when we’re logging so that we don’t see so many items.

For example, we can write:

const { MongoClient, Logger } = require('mongodb');
const connection = "mongodb://localhost:27017";
const client = new MongoClient(connection);

async function run() {
  try {
    Logger.setLevel("debug");
    Logger.filter("class", ["Db"]);
    await client.connect();
    const db = client.db("test");
    db.dropCollection('test');
    db.createCollection('test');
    const testCollection = await db.collection('test');
    const result = await testCollection.insertMany([
      { "_id": 1, "name": "apples", "qty": 5, "rating": 3 },
      { "_id": 2, "name": "apples", "qty": 7, "rating": 1 },
      { "_id": 3, "name": "oranges", "qty": 6, "rating": 2 },
      { "_id": 4, "name": "avocados", "qty": 3, "rating": 5 },
    ]);
    console.log(result)
    const cursor = await testCollection.find();
    cursor.forEach(console.dir);
  } finally {
    await client.close();
  }
}
run().catch(console.dir);

The Logger.filter method with the ['Db'] array lets us display messages that are on the 'Db' class.

We can also customize the logger with our own class.

For example, we can write:

const { MongoClient, Logger } = require('mongodb');
const connection = "mongodb://localhost:27017";
const client = new MongoClient(connection);

class CustomLogger {
  constructor() {
    this.logger = new Logger("A");
  }

log() {
    if (this.logger.isInfo()) {
      this.logger.info("logging A", {});
    }
  }
}

async function run() {
  try {
    const customLogger = new CustomLogger();
    customLogger.log();
    await client.connect();
    const db = client.db("test");
    db.dropCollection('test');
    db.createCollection('test');
    const testCollection = await db.collection('test');
    const result = await testCollection.insertMany([
      { "_id": 1, "name": "apples", "qty": 5, "rating": 3 },
      { "_id": 2, "name": "apples", "qty": 7, "rating": 1 },
      { "_id": 3, "name": "oranges", "qty": 6, "rating": 2 },
      { "_id": 4, "name": "avocados", "qty": 3, "rating": 5 },
    ]);
    console.log(result)
    const cursor = await testCollection.find();
    cursor.forEach(console.dir);
  } finally {
    await client.close();
  }
}
run().catch(console.dir);

We created the CustomLogger class and used its log method to do the logging.

Also, we can call setCurrentLogger to set a custom logger function:

const { MongoClient, Logger } = require('mongodb');
const connection = "mongodb://localhost:27017";
const client = new MongoClient(connection);

async function run() {
  try {
    Logger.setLevel("debug");
    Logger.setCurrentLogger((msg, context) => {
      context['foo'] = 'bar';
      msg = `Hello, World. ${msg}`;
      console.log(msg, context);
    });
    await client.connect();
    const db = client.db("test");
    db.dropCollection('test');
    db.createCollection('test');
    const testCollection = await db.collection('test');
    const result = await testCollection.insertMany([
      { "_id": 1, "name": "apples", "qty": 5, "rating": 3 },
      { "_id": 2, "name": "apples", "qty": 7, "rating": 1 },
      { "_id": 3, "name": "oranges", "qty": 6, "rating": 2 },
      { "_id": 4, "name": "avocados", "qty": 3, "rating": 5 },
    ]);
    console.log(result)
    const cursor = await testCollection.find();
    cursor.forEach(console.dir);
  } finally {
    await client.close();
  }
}
run().catch(console.dir);

The msg parameter has the message. The context has additional data about the event that’s logged.

Conclusion

We can add a logger to our MongoDB code with the Node.js MongoDB client.

Categories
MongoDB Node.js Basics

Node.js Basics — Specify Which Fields to Return with MongoDB

Node.js is a popular runtime platform to create programs that run on it.

It lets us run JavaScript outside the browser.

In this article, we’ll look at how to start using Node.js to create programs.

Specify Which Fields to Return with MongoDB

We can specify the fields that we want to return for each entry/.

For example, we can wrote:

const { MongoClient } = require('mongodb');
const connection = "mongodb://localhost:27017";
const client = new MongoClient(connection);

async function run() {
  try {
    await client.connect();
    const testCollection = await client.db("test").collection('test');
    await testCollection.deleteMany({})
    const result = await testCollection.insertMany([
      { "_id": 1, "name": "apples", "qty": 5, "rating": 3 },
      { "_id": 2, "name": "bananas", "qty": 7, "rating": 1 },
      { "_id": 3, "name": "oranges", "qty": 6, "rating": 2 },
      { "_id": 4, "name": "avocados", "qty": 3, "rating": 5 },
    ]);
    console.log(result)
    const projection = { name: 1 };
    const cursor = testCollection.find().project(projection);
    await cursor.forEach(console.dir);
  } finally {
    await client.close();
  }
}
run().catch(console.dir);

We call the project method with an object that has the keys that we want to include in the keys.

The value is 1 means we include the given property in the result.

The _id field is returned automatically by default.

So we get:

{ _id: 1, name: 'apples' }
{ _id: 2, name: 'bananas' }
{ _id: 3, name: 'oranges' }
{ _id: 4, name: 'avocados' }

returned.

If we want to disable this, then we can write:

const { MongoClient } = require('mongodb');
const connection = "mongodb://localhost:27017";
const client = new MongoClient(connection);

async function run() {
  try {
    await client.connect();
    const testCollection = await client.db("test").collection('test');
    await testCollection.deleteMany({})
    const result = await testCollection.insertMany([
      { "_id": 1, "name": "apples", "qty": 5, "rating": 3 },
      { "_id": 2, "name": "bananas", "qty": 7, "rating": 1 },
      { "_id": 3, "name": "oranges", "qty": 6, "rating": 2 },
      { "_id": 4, "name": "avocados", "qty": 3, "rating": 5 },
    ]);
    console.log(result)
    const projection = { _id: 0, name: 1 };
    const cursor = testCollection.find().project(projection);
    await cursor.forEach(console.dir);
  } finally {
    await client.close();
  }
}
run().catch(console.dir);

Then we get:

{ name: 'apples' }
{ name: 'bananas' }
{ name: 'oranges' }
{ name: 'avocados' }

We can specify multiple fields in the query.

For example, we can write:

const { MongoClient } = require('mongodb');
const connection = "mongodb://localhost:27017";
const client = new MongoClient(connection);

async function run() {
  try {
    await client.connect();
    const testCollection = await client.db("test").collection('test');
    await testCollection.deleteMany({})
    const result = await testCollection.insertMany([
      { "_id": 1, "name": "apples", "qty": 5, "rating": 3 },
      { "_id": 2, "name": "bananas", "qty": 7, "rating": 1 },
      { "_id": 3, "name": "oranges", "qty": 6, "rating": 2 },
      { "_id": 4, "name": "avocados", "qty": 3, "rating": 5 },
    ]);
    console.log(result)
    const projection = { _id: 0, rating: 1, name: 1 };
    const cursor = testCollection.find().project(projection);
    await cursor.forEach(console.dir);
  } finally {
    await client.close();
  }
}
run().catch(console.dir);

Then, we get:

{ name: 'apples', rating: 3 }
{ name: 'bananas', rating: 1 }
{ name: 'oranges', rating: 2 }
{ name: 'avocados', rating: 5 }

returned.

Conclusion

We can select the fields we return with MongoDB queries.

Categories
MongoDB Node.js Basics

Node.js Basics — MongoDB Text and Unique Indexes

Node.js is a popular runtime platform to create programs that run on it.

It lets us run JavaScript outside the browser.

In this article, we’ll look at how to start using Node.js to create programs.

Text Indexes

Text indexes let us do text searches on queries that have string content.

It can include any field whose value is a string or an array of strings.

For example, we can create the index and use it by wriing”

const { MongoClient } = require('mongodb');
const connection = "mongodb://localhost:27017";
const client = new MongoClient(connection);

async function run() {
  try {
    await client.connect();
    const db = client.db("test");
    const testCollection = await db.collection('test');
    await testCollection.dropIndexes();
    const indexResult = await testCollection.createIndex({ name: "text" }, { default_language: "english" });
    console.log(indexResult)
    await testCollection.deleteMany({})
    const result = await testCollection.insertMany([
      { "_id": 1, "name": "apples", "qty": 5, "rating": 3 },
      { "_id": 2, "name": "bananas", "qty": 7, "rating": 1 },
      { "_id": 3, "name": "oranges", "qty": 6, "rating": 2 },
      { "_id": 4, "name": "avocados", "qty": 3, "rating": 5 },
    ]);
    console.log(result)
    const query = { $text: { $search: "apple" } };
    const projection = { name: 1 };
    const cursor = testCollection
      .find(query)
      .project(projection);
    cursor.forEach(console.dir);
  } finally {
    await client.close();
  }
}
run().catch(console.dir);

We create the index by writing:

const indexResult = await testCollection.createIndex({ name: "text" }, { default_language: "english" });

The createIndex method adds the index to the name field.

The 2nd argument has the options for creating the index.

The default_language sets the index language.

Unique Indexes

We can add a unique index that index fields that don’t store duplicate values.

The _id field has a unique index added to it when the collection is created.

For example, we can write:

const { MongoClient } = require('mongodb');
const connection = "mongodb://localhost:27017";
const client = new MongoClient(connection);

async function run() {
  try {
    await client.connect();
    const db = client.db("test");
    const testCollection = await db.collection('test');
    await testCollection.dropIndexes();
    const indexResult = await testCollection.createIndex({ name: "text" }, { unique: true });
    console.log(indexResult)
    await testCollection.deleteMany({})
    const result = await testCollection.insertMany([
      { "_id": 1, "name": "apples", "qty": 5, "rating": 3 },
      { "_id": 2, "name": "bananas", "qty": 7, "rating": 1 },
      { "_id": 3, "name": "oranges", "qty": 6, "rating": 2 },
      { "_id": 4, "name": "avocados", "qty": 3, "rating": 5 },
    ]);
    console.log(result)
    const query = {};
    const projection { name: 1 };
    const cursor = testCollection
      .find(query)
      .project(projection);
    cursor.forEach(console.dir);
  } finally {
    await client.close();
  }
}
run().catch(console.dir);

to call createIndex with the 2nd argument being an object with the unique property set to true .

If there’re any duplicate values in the field in the collection, then we get the ‘duplicate key error index’ error when we try to create the index.

Conclusion

We can add indexes for text searches and indexing unique values for MongoDB fields.

Categories
MongoDB Node.js Basics

Node.js Basics — MongoDB Promises and Callbacks

Node.js is a popular runtime platform to create programs that run on it.

It lets us run JavaScript outside the browser.

In this article, we’ll look at how to start using Node.js to create programs.

Promises and Callbacks

The MongoDB client has methods that return promises.

They’re async code that can have the status pending before it has the result.

Once it has a result, the it can be fulfilled if the operation is done successfully.

Otherwise, it has the rejected status.

For example, the updateOne method returns a promise.

We can use it by writing:

const { MongoClient } = require('mongodb');
const connection = "mongodb://localhost:27017";
const client = new MongoClient(connection);

async function run() {
  try {
    await client.connect();
    const testCollection = await client.db("test").collection('test');
    await testCollection.deleteMany({})
    const result = await testCollection.insertMany([
      { "_id": 1, "name": "apples", "qty": 5, "rating": 3 },
      { "_id": 2, "name": "bananas", "qty": 7, "rating": 1 },
      { "_id": 3, "name": "oranges", "qty": 6, "rating": 2 },
      { "_id": 4, "name": "avocados", "qty": 3, "rating": 5 },
    ]);
    console.log(result)
    const updateResult = await testCollection
      .updateOne({ name: "apple" }, { $set: { qty: 100 } })
    console.log(updateResult);
  } finally {
    await client.close();
  }
}
run().catch(console.dir);

We call updateOne with the await keyword so that we can get the resolved value once we have it.

updateOne returns a promise, so we can use the await keyword.

If we want to catch errors, then we can write:

const { MongoClient } = require('mongodb');
const connection = "mongodb://localhost:27017";
const client = new MongoClient(connection);

async function run() {
  try {
    await client.connect();
    const testCollection = await client.db("test").collection('test');
    await testCollection.deleteMany({})
    const result = await testCollection.insertMany([
      { "_id": 1, "name": "apples", "qty": 5, "rating": 3 },
      { "_id": 2, "name": "bananas", "qty": 7, "rating": 1 },
      { "_id": 3, "name": "oranges", "qty": 6, "rating": 2 },
      { "_id": 4, "name": "avocados", "qty": 3, "rating": 5 },
    ]);
    console.log(result)
    try {
      const updateResult = await testCollection
        .updateOne({ name: "apple" }, { $set: { qty: 100 } })
      console.log(updateResult);
    } catch (error) {
      console.log(`Updated ${res.result.n} documents`)
    }

} finally {
    await client.close();
  }
}
run().catch(console.dir);

to add a catch block to log any errors that’s raised from the rejected promise.

Callbacks

We can also use callbacks to get the result of an operation.

For example, we can write:

const { MongoClient } = require('mongodb');
const connection = "mongodb://localhost:27017";
const client = new MongoClient(connection);

async function run() {
  try {
    await client.connect();
    const testCollection = await client.db("test").collection('test');
    await testCollection.deleteMany({})
    const result = await testCollection.insertMany([
      { "_id": 1, "name": "apples", "qty": 5, "rating": 3 },
      { "_id": 2, "name": "bananas", "qty": 7, "rating": 1 },
      { "_id": 3, "name": "oranges", "qty": 6, "rating": 2 },
      { "_id": 4, "name": "avocados", "qty": 3, "rating": 5 },
    ]);
    console.log(result)
    testCollection
      .updateOne({ name: "apple" }, { $set: { qty: 100 } }, (error, result) => {
        if (!error) {
          console.log(`Operation completed successfully`);
        } else {
          console.log(`An error occurred: ${error}`);
        }
      })
  } finally {
    await client.close();
  }
}
run().catch(console.dir);

We call updateOne with a callback in the 3rd argument.

This lets us get the async result with the callback instead of returning a promise.

Conclusion

The MongoDB client returns promises or we can use callbacks to get the result from an async operation.