MacLochlainns Weblog

Michael McLaughlin's Technical Blog

Site Admin

Archive for the ‘MongoDB Developer’ tag

MongoDB on macOS

without comments

It’s important to document things before I ask my students to do them. This walks through a native installation of MongoDB on the macOS. At least, it does when you’ve already installed Xcode. If you installed Xcode sometime ago, you should update it otherwise you may get an installation error like the following:

==> Installing mongodb-community from mongodb/brew
Error: Your Xcode (11.1) is too outdated.
Please update to Xcode 13.1 (or delete it).
Xcode can be updated from the App Store.

The core MongoDB installation document is in the MongoDB 5.0 installation manual. The following is a step-by-step set of instructions for those new to installing something like MongoDB without using the macOS standard package management software.

  1. The first step requires you install Home Brew, as qualified by the Home Brew Installation page. Before you can install Home Brew, you need to install Xcode on your macOS. After installing Xcode, you need to launch a Terminal session on your macOS and run the following command from the macOS command-line interface (CLI):

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

    After the installation, which may take several minutes, you should see this final message on the console:

    ==> Next steps:
    - Run brew help to get started
    - Further documentation:
        https://docs.brew.sh
  2. Now that Home Brew is installed, the next step requires you to update the Homebrew formulat for MongoDB. You use the following command to do that for MongoDB 5:

    brew tap mongodb/brew

    You should see something like the following on your console when you update the Homebrew formula:

    Running `brew update --preinstall`...
    ==> Homebrew is run entirely by unpaid volunteers. Please consider donating:
      https://github.com/Homebrew/brew#donations
    ==> Auto-updated Homebrew!
    Updated 1 tap (homebrew/core).
    ==> Updated Formulae
    Updated 5 formulae.
     
    ==> Tapping mongodb/brew
    Cloning into '/usr/local/Homebrew/Library/Taps/mongodb/homebrew-brew'...
    remote: Enumerating objects: 825, done.
    remote: Counting objects: 100% (322/322), done.
    remote: Compressing objects: 100% (236/236), done.
    remote: Total 825 (delta 165), reused 140 (delta 83), pack-reused 503
    Receiving objects: 100% (825/825), 180.91 KiB | 0 bytes/s, done.
    Resolving deltas: 100% (403/403), done.
    Tapped 14 formulae (30 files, 246.8KB).
  3. Assuming your Xcode is curent, you now install MongoDB with the necessary supporting packages:

    brew install mongodb-community@5.0

    You should see something like the following on your console after you install MongoDB 5:

    ==> Summary
      /usr/local/Cellar/mongodb-community/5.0.5: 11 files, 181.5MB, built in 6 seconds
    ==> Running `brew cleanup mongodb-community`...
    Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
    Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
    ==> Caveats
    ==> mongodb-community
    To start mongodb/brew/mongodb-community now and restart at login:
      brew services start mongodb/brew/mongodb-community
    Or, if you don't want/need a background service you can just run:
      mongod --config /usr/local/etc/mongod.conf
  4. MongoDB really requires a background service, so I suggest you use the following to create the service:

    brew services start mongodb/brew/mongodb-community

    You should see something like the following on your console after you install MongoDB 5:

    ==> Successfully started `mongodb-community` (label: homebrew.mxcl.mongodb-community)

    The installation gave you three key binaries:

    • The MongoDB Server Daemon – mongod
    • The MongoDB sharded cluster query router – mongos
    • The MongoDB Shell – mongosh

    The installation also creates configuration, data, and log files based on physical CPU-Chip hardware:

    • Intel Processor
      • Configuration File: /usr/local/etc/mongodb.conf
      • Log Directory: /usr/local/var/log/mongodb
      • Data Directory: /usr/local/var/mongodb
    • Apple M1 Processor
      • Configuration File: /opt/homebrew/etc/mongodb.conf
      • Log Directory: /opt/homebrew/var/log/mongodb
      • Data Directory: /opt/homebrew/var/mongodb
    • You can now start the MongoDB Shell with the following command in a Terminal window:

      mongosh

      You should see the following when you connect to the MongoDB Shell

      Current Mongosh Log ID:	61e4e2c98f023c2b5fc5a905
      Connecting to:		mongodb://127.0.0.1:27017/?directConnection=true&serverSelectionTimeoutMS=2000
      Using MongoDB:		5.0.5
      Using Mongosh:		1.1.8
       
      For mongosh info see: https://docs.mongodb.com/mongodb-shell/
       
       
      To help improve our products, anonymous usage data is collected and sent to MongoDB periodically (https://www.mongodb.com/legal/privacy-policy).
      You can opt-out by running the disableTelemetry() command.
       
      ------
         The server generated these startup warnings when booting:
         2022-01-16T20:26:18.320-07:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
      ------
       
      test>

As always, I hope the instructions are helpful and clear. If you find an issue let em know about it.

Written by maclochlainn

January 16th, 2022 at 8:45 pm

Fun JavaScript Q?

without comments

I got sent a fun JavaScript question from a student. It was fun for two reasons. They were clearly engaged and trying to figure stuff out on their own and they were just beyond basic syntax issues.

The student wanted to know why this code worked:

// Populate an object with one property.
var notempty = {test:"me"}
 
// Test for and enumerate object properties.
for (var property in notempty) {
  if (!notempty.hasOwnProperty(property)) {
    print("No properties")
  }
  else {
    print("[" + property + "]")
  }
}
print("done")

and returned:

[test]
done

but the behavior changed when the initialized object didn’t have any properties. It failed to print the No properties message:

// Populate an object with one property.
var empty = {}
 
// Test for and enumerate object properties.
for (var property in empty) {
  if (!empty.hasOwnProperty(property)) {
    print("No properties")
  }
  else {
    print("[" + property + "]")
  }
} print("done")

it printed:

done

The answer was easy, there were no properties to enumerate, which meant the loop never executes. However, that’s only part of the answer. The complete answer is that the empty object and the default Object.prototype have no properties to enumerate. You should perform a different test before the loop, like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Populate an object without properties.
var empty = {}
 
// Test for and enumerate object properties.
if (Object.keys(empty).length !== 0) {
  for (var property in empty) {
    if (empty.hasOwnProperty(property)) {
      print("[" + property + "]")
    }
  }
} else {
  print("No properties")
}
 
// Print complete message.
print("done")

If you run this from the mongo shell, like this

mongo --nodb --norc < object_properties.js

It prints:

MongoDB shell version v4.0.19
No properties
done
bye

If you run this inside the mongo shell with the load function, like

load("object_properties.js")

It prints:

No properties
done
true

However, you can generate a parsing error when you rewrite line 11 in the if-else statement, like so

if (Object.keys(empty).length !== 0) {
  ...
}
else {
  ...
}

The reason for the error is that JavaScript appends a semicolon (;) at the end of each line. Therefore, the if-else-statement appears as an if-only-statement. which raises the syntax error.

It prints:

MongoDB shell version v4.0.19
2021-08-02T13:38:34.672-0600 E QUERY    [js] SyntaxError: expected expression, got keyword 'else' @(shell):1:0
done
bye

It appears the parsing error is a warning message because the code completes. Personally, I would prefer that they not raise a warning message because it actually implies a style preference.

There’s a next level problem you may run into while trying to implement reflection, or the discovery of existing properties and their value types, of JavaScript objects. Here’s that code, which seems to be missing from many tutorials and articles:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Create an object with functions.
// Populate an object without properties.
var notEmpty = { first_name: "Clark"
               , last_name: "Kent"
               , getName: function() { return this.first_name + " " + this.last_name }
               }
 
// Test for and enumerate object properties.
if (Object.keys(notEmpty).length !== 0) {
  for (var property in notEmpty) {
    if (notEmpty.hasOwnProperty(property)) {
      print("[" + property + "] value is a [" + typeof(notEmpty[property]) + "]")
    }
  }
} else {
  print("No properties")
}
 
print("done")

This code on line 12 lets you view a property’s value type:

1
typeof(notEmpty[property])

Only the object[property] subscript notation method works when the property’s value is a variable. The other dot notation syntax to access a property’s value in JavaScript, object.property, doesn’t work without a literal value. Actually, it would work if you embed it inside an eval() function call, but the eval() function is bad juju (black magic) in JavaScript coding.

It prints the following:

MongoDB shell version v4.0.19
[first_name] value is a [string]
[last_name] value is a [string]
[getName] value is a [function]
done
bye

While this shows the basic functionality, it would be more effective to create a function and extend it while adding some output formatting. The next example wouldn’t be found in a JSON (JavaScript Object Notation) collection element but would be found in a NodeJS application managing JSON structures. You would define the constructor to match the data properties of the JSON structure.

The nice thing about a JavaScript function is that “It can specify a list of parameters that will act as variables initialized by the invocation arguments. The body of the function includes variable definitions and statement. (JavaScript: The Good Parts, 2008)” Newer approaches allow you to pass an object as a parameter with named notation inside the object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// Create an object with functions.
function Person(first_name, last_name) {
             this.first_name = first_name
           , this.last_name  = last_name
           , this.setFirstName =
               function(first_name) {
                 this.first_name = first_name }
           , this.getName =
               function() {
                 return this.first_name + " " + this.last_name }
         }
 
// Create an instance of a variable and print results.
var myPerson = new Person("Clark","Kent")
print("Initial Name: " + myPerson.getName())
 
// Call the added function and print the new value.
myPerson.setFirstName("Lois")
print("Reset Name:   " + myPerson.getName())
print()
 
// Test for and enumerate object properties.
print("Variable Property Names & Values")
print("====================================")
if (Object.keys(myPerson).length !== 0) {
  for (var property in myPerson) {
    if (myPerson.hasOwnProperty(property)) {
      print("[" + property + "] value is a [" + typeof(myPerson[property]) + "]")
    }
  }
} else {
  print("No properties")
}
print("====================================")
print("done")

It prints the following:

MongoDB shell version v4.0.19
Initial Name: Clark Kent
Reset Name:   Lois Kent
 
Variable Property Names & Values
====================================
[first_name] value is a [string]
[last_name] value is a [string]
[setFirstName] value is a [function]
[getName] value is a [function]
====================================
done
bye

While the prior example shows object construction, this one introduces one variable inheriting the Person function’s properties and another inheriting the same properties before adding a new one to only the variable. The inherited properties, which are functions, are methods of the variable by delegation.

Below is the modified code. It changes the variable from myPerson to myPerson1 and lines 22 through 28 add the new myPerson2 variable and setLastName function. Lines 47 to 58 enumerate across the new second variable, myPerson2 to show you that it has a new setLastName function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// Create an object with functions.
function Person(first_name, last_name) {
             this.first_name = first_name
           , this.last_name  = last_name
           , this.setFirstName =
               function(first_name) {
                 this.first_name = first_name }
           , this.getName =
               function() {
                 return this.first_name + " " + this.last_name }
         }
 
// Create an instance of a variable and print results.
var myPerson1 = new Person("Clark","Kent")
print("Initial Name: " + myPerson1.getName())
 
// Call the added function and print the new value.
myPerson1.setFirstName("Lois")
print("Reset Name:   " + myPerson1.getName())
print()
 
// Create an instance of a variable and print results.
var myPerson2 = new Person("Bruce","Wayne")
print("Initial Name: " + myPerson2.getName())
 
// Add a function to the local variable.
function setLastName(last_name) { this.last_name = last_name }
myPerson2.setLastName = setLastName
print()
 
// Test for and enumerate object properties.
print("Variable Property Names & Values")
print("====================================")
if (Object.keys(myPerson1).length !== 0) {
  for (var property in myPerson1) {
    if (myPerson1.hasOwnProperty(property)) {
      print("[" + property + "] value is a [" + typeof(myPerson1[property]) + "]")
    }
  }
} else {
  print("No properties")
}
print("====================================")
print()
 
// Test for and enumerate object properties.
print("Variable Property Names & Values")
print("====================================")
if (Object.keys(myPerson2).length !== 0) {
  for (var property in myPerson2) {
    if (myPerson2.hasOwnProperty(property)) {
      print("[" + property + "] value is a [" + typeof(myPerson2[property]) + "]")
    }
  }
} else {
  print("No properties")
}
print("====================================")
print("done")

The program shows you the following output:

MongoDB shell version v4.0.19
Initial Name: Clark Kent
Reset Name:   Lois Kent
 
Initial Name: Bruce Wayne
 
Variable Property Names & Values
====================================
[first_name] value is a [string]
[last_name] value is a [string]
[setFirstName] value is a [function]
[getName] value is a [function]
====================================
 
Variable Property Names & Values
====================================
[first_name] value is a [string]
[last_name] value is a [string]
[setFirstName] value is a [function]
[getName] value is a [function]
[setLastName] value is a [function]
====================================
done
bye

As always, I hope this helps those working through a similar issue.

Written by maclochlainn

August 2nd, 2021 at 5:21 pm

MongoDB Duplicate Key

without comments

How do you avoid encountering a “duplicate key on update” in MongoDB? Well, that’s an interesting question if you’re coming at it from a relational perspective. The answer is understanding that while there may be a natural key, the update needs to use the unique identifier (or, _id). The unique identifier is essentially a primary key based on a system generated surrogate key, assigned by the insertOne() or insertMany() methods. As you’ll notice in the example, it’s not just a numeric value.

The following builds you a test case and is designed to run from the interactive mongo shell. It assumes you understand enough JavaScript to read the code dealing with the JSON (JavaScript Object Notation) structure.

  1. Insert three rows in a people collection with the insertMany() method:

    > db.people.insertMany([
    ...  {"name" : "joe", "age" : 65}
    ... ,{"name" : "joe", "age" : 20}
    ... ,{"name" : "joe", "age" : 49}])

    it returns the following unique identifiers:

    {
            "acknowledged" : true,
            "insertedIds" : [
                    ObjectId("60a4a67f8d03d82365e994ab"),
                    ObjectId("60a4a67f8d03d82365e994ac"),
                    ObjectId("60a4a67f8d03d82365e994ad")
            ]
    }
  2. Assign the return value from a findOne() method against the people collection to a joe variable:

    > joe = db.people.findOne({"name" : "joe", "age" : 20})

    Typically, you can print local variables in the mongo shell with the print command, like:

    print(joe)

    it returns the following:

    [object BSON]

    The object is a Binary JSON object, which requires you use the following command:

    printjson(joe)

    It prints the following JSON element:

    { "_id" : ObjectId("60a4a67f8d03d82365e994ac"), "name" : "joe", "age" : 20 }
  3. Increment the age value from 20 to 21:

    > joe.age++

    You can show the change in the age member’s value by printing the JSON element with the printjson() function:

    { "_id" : ObjectId("60a4a67f8d03d82365e994ac"), "name" : "joe", "age" : 21 }
  4. If you attempt to replace the JSON structure in the MongoDB collection with anything other than the following, you’ll raise a duplicate key error. You must reference the _id value to update the correct element of the collection. The following syntax works:

    db.people.replaceOne({"_id" : joe._id}, joe)

    it should return the following:

    { "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

    You can verify that the change only affected the originally queried row with the following command:

    db.people.find()

    it should return the following:

    { "_id" : ObjectId("60a4a67f8d03d82365e994ab"), "name" : "joe", "age" : 65 }
    { "_id" : ObjectId("60a4a67f8d03d82365e994ac"), "name" : "joe", "age" : 21 }
    { "_id" : ObjectId("60a4a67f8d03d82365e994ad"), "name" : "joe", "age" : 49 }

I thought this example may help others because the O’Reily’s MongoDB: The Definitive Guide example (on pages 35-37) uses a manually typed string, which doesn’t lend itself to a programmatic solutions. It also failed to clarify that value returned from the findOne() method and assigned to the local joe variable would be a BSON (Binary JSON) object; and it didn’t cover any means to easily convert the BSON to a JSON text. The reality is there’s no necessity to cast the BSON into a JSON object, also left out of the text. All that said, it’s still an excellent, if not essential, book for your technical library if you’re working with the MongoDB database.

Written by maclochlainn

May 22nd, 2021 at 11:09 pm

MongoDB Two Step

without comments

Sometimes a bit of humor helps with a new topic. Creating a database in MongoDB is a two-step process, like the Texas Two-Step (a nick name for a country/western two-step danced in common time). A Texas Two Step is a one-two, one-two shuffle which is like the two-step process for how you create a MongoDB database.

While databases in MongoDB are a multiuser sandbox like a relational database, you can’t simply create them and grant them privileges. You must first USE the database and then put a collection (a.k.a., equivalent to a table in MySQL) in it. This blog post shows you how to create a MongoDB play database with an actor collection. It shows you the commands to create the a database with one collection in it and how to verify its existence.

You connect through the mongo shell, like:

mongo

The first-step requires you to connect to the play database even though it doesn’t exist. You do that by typing:

> use play

You can verify you’re in the play database by typing the db command, which the mongo shell treats as an expression. It returns play, as the name of the current database.

However, when you call the shell show dbs helper:

> show dbs

It displays:

admin   0.000GB
config  0.000GB
local   0.000GB

You also should note that the play database still doesn’t exist when you run the JavaScript equivalent to the shell show dbs helper:

> db.getMongo().getDBs()

It returns the following list of databases, which excludes the as yet not created play database:

{
  "databases" : [
    {
      "name" : "admin",
      "sizeOnDisk" : 32768,
      "empty" : false
    },
    {
      "name" : "config",
      "sizeOnDisk" : 61440,
      "empty" : false
    },
    {
      "name" : "local",
      "sizeOnDisk" : 81920,
      "empty" : false
    }
  ],
  "totalSize" : 176128,
  "ok" : 1
}

You create an actor collection (a.k.a. the equivalent of a relational table) with the following syntax, where db maps to the play database that you’re using. Note that you must create or insert one document to begin a document collection. While you can use the insert method, you should use either the newer insertOne() or insertMany() methods.

> db.actors.insertOne({"actor" : {"first_name" : "Chris", "last_name" : "Pine"}, "age" : 40 })

A new call to the shell show dbs helper:

> show dbs

displays your new play database:

admin   0.000GB
config  0.000GB
local   0.000GB
play    0.000GB

You can add two more documents (a.k.a. for rows in a relational database) with the insertMany() method:

> db.actors.insertMany([{"actor" : {"first_name" : "Chris", "last_name" : "Evans"}, "age" : 39 }
                       ,{"actor" : {"first_name" : "Chris", "last_name" : "Pratt"}, "age" : 41 }])

A quick word to the JavaScript novices out there. Don’t forget the square brackets ([{},{},...]) in the insertMany() method call or you’ll get an error like this:

2021-04-12T16:20:13.237-0600 E QUERY    [js] TypeError: documents.map is not a function :
DBCollection.prototype.insertMany@src/mongo/shell/crud_api.js:295:1
@(shell):1:1

You call the shell show collections helper or db.getMongo().getCollectionNames() JavaScript function to display the collections in the play database. The show collections displays a list of collections, and the db.getMongo().getCollectionNames() displays an JavaScript array of collections.

If you’re like me, Mongo’s db convention is a bit risky that I could do something in the wrong database. So, I put the following function into my .mongorc.js (a.k.a., MongoDB Resource file):

prompt = function() { var dbName = db; return dbName + "> " }

It ensures you will see the current database name to the left of the prompt (“>”), like:

play>

You can query the documents from the actors collection with the following:

play> db.actors.find().pretty()

It returns:

{
  "_id" : ObjectId("6074c692813c5a85db9cc9df"),
  "actor" : {
    "first_name" : "Chris",
    "last_name" : "Pine"
  },
  "age" : 40
}
{
  "_id" : ObjectId("6074c7ea813c5a85db9cc9e0"),
  "actor" : {
    "first_name" : "Chris",
    "last_name" : "Evans"
  },
  "age" : 39
}
{
  "_id" : ObjectId("6074c7ea813c5a85db9cc9e1"),
  "actor" : {
    "first_name" : "Chris",
    "last_name" : "Pratt"
  },
  "age" : 41
}

As always, I hope this helps those looking for a solution.

Written by maclochlainn

April 12th, 2021 at 5:57 pm

MongoDB Script Test

without comments

There are many ways to test and edit files. A lot of developers only use their favorite Integrated Developer Environment (IDE) but I find testing script files within the scope of a pipelined set of scripts much faster.

The ability to edit a JavaScript file from within the mongo Shell would be nice but unfortunately, it doesn’t exist. You are able to edit a complex variable with a mechanism quite like the Oracle Database. Rather than leave you hanging on how to edit a complex variable in the mongo shell, here are the steps before launching into how to test your JavaScript files:

  1. You can enter this manually during any connection to the mongo shell or put it in your .mongorc.js configuration file, like this in Fedora with the fully qualified filename:

    EDITOR="/usr/bin/vim"
  2. Let’s say you have a stooges array variable that contains “Moe”, “Curly”, and “Larry” and you want to add “Shemp” to the variable. You can edit the stooges array variable with vi and add “Shemp” to it by typing edit and the stooges variable name.

    edit stooges
  3. Then, you can test the stooges array variable’s new values:

    stooges
  4. It returns the following:

    [ "Moe", "Curly", "Shemp", "Larry" ]

Unfortunately, these changes to the demo array variable will be lost after you break the connection. While it does afford a quick test case, you should make the changes in the external JavaScript file. Then, the change is there the the next time you access the resource file.

Here’s my quick edit and test script technique for MongoDB from your present working directory:

  1. Assume you create a compliment.js test file, like:

    /* Declare an array variable and random index value. */
    var compliment = ["Bashful","Doc","Dopey","Grumpy","Happy","Sleepy","Sneezy"]
    var index = Math.floor(Math.random()*7)
     
    /* Print a welcome message. */
    print("Hello, " + compliment[index] + ".")
  2. You can edit the compliment.js file with vi and test the script interactively from the present working directory.

    • You can edit the file with the following syntax:

      vi compliment.js
    • then, you can test the task.sql file:

      mongo --nodb --norc < compliment.js
    • The --nodb option instructs MongoDB to not connect to a database and the --norc option instructs MongoDB to not load your .mongorc.js file. Effectively, disabling the database connection and loading of the MongoDB resource file (.mongorc.js) lets you test your code in MongoDB’s Javascript shell unencumbered by any overhead from the MongoDB server.

      The foregoing script returns the following:

      MongoDB shell version v4.0.19
      Hello, Sneezy.
      bye
    • If you have the desired outcome, you’re done. However, if you need further change you repeat the process.

As always, I hope this helps those looking for a quick way to accomplish a task.

Written by maclochlainn

April 11th, 2021 at 1:45 pm

MongoDB on Fedora 30

without comments

I found that MongoDB instructions changed significantly from a year ago. More or less, there was no pre-configured yum repository. Fortunately, the following web page was very helpful though not specific about Fedora.

Installing MongoDB 4.0 on Fedora 30 requires updating the yum repository. You need to create the mongodb.repo file as the root user in the /etc/yum.repos.d directory. The mongodb.repo file should contain the following:

[Mongodb]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/amazon/2013.03/mongodb-org/4.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.0.asc

After you create the appropriate mongodb.repo file, you can run the following command to install the MongoDB database.

def install mongodb-org

It will produce the following log:

MongoDB Repository                            31 kB/s |  21 kB     00:00    
Dependencies resolved.
=============================================================================
 Package                 Arch        Version              Repository    Size
=============================================================================
Installing:
 mongodb-org             x86_64      4.0.12-1.amzn1       Mongodb      5.8 k
Installing dependencies:
 mongodb-org-mongos      x86_64      4.0.12-1.amzn1       Mongodb       11 M
 mongodb-org-server      x86_64      4.0.12-1.amzn1       Mongodb       20 M
 mongodb-org-shell       x86_64      4.0.12-1.amzn1       Mongodb       13 M
 mongodb-org-tools       x86_64      4.0.12-1.amzn1       Mongodb       29 M
 
Transaction Summary
=============================================================================
Install  5 Packages
 
Total download size: 73 M
Installed size: 213 M
Is this ok [y/N]: y
Downloading Packages:
(1/5): mongodb-org-4.0.12-1.amzn1.x86_64.rpm  18 kB/s | 5.8 kB     00:00    
(2/5): mongodb-org-shell-4.0.12-1.amzn1.x86_ 4.6 MB/s |  13 MB     00:02    
(3/5): mongodb-org-mongos-4.0.12-1.amzn1.x86 1.8 MB/s |  11 MB     00:06    
(4/5): mongodb-org-tools-4.0.12-1.amzn1.x86_ 6.6 MB/s |  29 MB     00:04    
(5/5): mongodb-org-server-4.0.12-1.amzn1.x86 2.5 MB/s |  20 MB     00:08    
-----------------------------------------------------------------------------
Total                                        9.0 MB/s |  73 MB     00:08     
warning: /var/cache/dnf/Mongodb-f722cd88d61a4e38/packages/mongodb-org-4.0.12-1.amzn1.x86_64.rpm: Header V3 RSA/SHA1 Signature, key ID e52529d4: NOKEY
MongoDB Repository                           3.0 kB/s | 1.7 kB     00:00    
Importing GPG key 0xE52529D4:
 Userid     : "MongoDB 4.0 Release Signing Key <packaging@mongodb.com>"
 Fingerprint: 9DA3 1620 334B D75D 9DCB 49F3 6881 8C72 E525 29D4
 From       : https://www.mongodb.org/static/pgp/server-4.0.asc
Is this ok [y/N]: y
Key imported successfully
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                     1/1 
  Installing       : mongodb-org-tools-4.0.12-1.amzn1.x86_64             1/5 
  Installing       : mongodb-org-shell-4.0.12-1.amzn1.x86_64             2/5 
  Running scriptlet: mongodb-org-server-4.0.12-1.amzn1.x86_64            3/5 
  Installing       : mongodb-org-server-4.0.12-1.amzn1.x86_64            3/5 
  Running scriptlet: mongodb-org-server-4.0.12-1.amzn1.x86_64            3/5 
  Installing       : mongodb-org-mongos-4.0.12-1.amzn1.x86_64            4/5 
  Installing       : mongodb-org-4.0.12-1.amzn1.x86_64                   5/5 
  Running scriptlet: mongodb-org-4.0.12-1.amzn1.x86_64                   5/5 
  Verifying        : mongodb-org-4.0.12-1.amzn1.x86_64                   1/5 
  Verifying        : mongodb-org-mongos-4.0.12-1.amzn1.x86_64            2/5 
  Verifying        : mongodb-org-server-4.0.12-1.amzn1.x86_64            3/5 
  Verifying        : mongodb-org-shell-4.0.12-1.amzn1.x86_64             4/5 
  Verifying        : mongodb-org-tools-4.0.12-1.amzn1.x86_64             5/5 
 
Installed:
  mongodb-org-4.0.12-1.amzn1.x86_64                                          
  mongodb-org-mongos-4.0.12-1.amzn1.x86_64                                   
  mongodb-org-server-4.0.12-1.amzn1.x86_64                                   
  mongodb-org-shell-4.0.12-1.amzn1.x86_64                                    
  mongodb-org-tools-4.0.12-1.amzn1.x86_64                                    
 
Complete!

You create a MongoDB service with the following syntax as a privileged user in the sudoer list:

sudo systemctl enable mongodb.service

You can then start the mongod service with the following command as a privileged user in the sudoer list:

sudo systemctl start mongod.service

You confirm that it started with the following command as the same privileged user:

sudo service mongod status

It should produce a log file like this:

● mongod.service - SYSV: Mongo is a scalable, document-oriented database.
   Loaded: loaded (/etc/rc.d/init.d/mongod; generated)
   Active: active (running) since Fri 2019-08-16 14:57:22 MDT; 2min 57s ago
     Docs: man:systemd-sysv-generator(8)
  Process: 128115 ExecStart=/etc/rc.d/init.d/mongod start (code=exited, stat>
    Tasks: 27 (limit: 4661)
   Memory: 47.0M
   CGroup: /system.slice/mongod.service
           └─128131 /usr/bin/mongod -f /etc/mongod.conf
 
Aug 16 14:57:21 localhost.localdomain systemd[1]: Starting SYSV: Mongo is a >
Aug 16 14:57:21 localhost.localdomain runuser[128127]: pam_unix(runuser:sess>
Aug 16 14:57:22 localhost.localdomain runuser[128127]: pam_unix(runuser:sess>
Aug 16 14:57:22 localhost.localdomain mongod[128115]: [30B blob data]
Aug 16 14:57:22 localhost.localdomain systemd[1]: Started SYSV: Mongo is a s>
lines 1-15/15 (END)

You close the service log with a “q“. You can determine your version with the following command:

mongod --version

It should show you something like this:

db version v4.0.12
git version: 5776e3cbf9e7afe86e6b29e22520ffb6766e95d4
OpenSSL version: OpenSSL 1.0.0-fips 29 Mar 2010
allocator: tcmalloc
modules: none
build environment:
    distmod: amazon
    distarch: x86_64
    target_arch: x86_64

You can connect to the MongoDB shell with the following command:

mongo

Inside the MongoDB shell, you can run standard MongoDB commands, like:

> use mydb;
switched to db mydb
> db.version()
4.0.12
> db.stats()
{
        "db" : "mydb",
        "collections" : 0,
        "views" : 0,
        "objects" : 0,
        "avgObjSize" : 0,
        "dataSize" : 0,
        "storageSize" : 0,
        "numExtents" : 0,
        "indexes" : 0,
        "indexSize" : 0,
        "fileSize" : 0,
        "fsUsedSize" : 0,
        "fsTotalSize" : 0,
        "ok" : 1
}
> quit()

As always, I hope this helps those looking for the missing steps.

Written by maclochlainn

August 16th, 2019 at 3:11 pm

Ruby GEM Mongo

without comments

While trying to use the Ruby gem utility to install the MongoDB gem, I encountered an error on a new Fedora 27 instance. This is the error message:

Fetching: bson-4.3.0.gem (100%)
Building native extensions.  This could take a while...
ERROR:  Error installing mongo:
        ERROR: Failed to build gem native extension.
 
    current directory: /usr/local/share/gems/gems/bson-4.3.0/ext/bson
/usr/bin/ruby -r ./siteconf20180517-49401-1htl7zc.rb extconf.rb
mkmf.rb can't find header files for ruby at /usr/share/include/ruby.h
 
extconf failed, exit code 1
 
Gem files will remain installed in /usr/local/share/gems/gems/bson-4.3.0 for inspection.
Results logged to /usr/local/lib64/gems/ruby/bson-4.3.0/gem_make.out
[student@localhost ~]$ ruby --version
ruby 2.4.3p205 (2017-12-14 revision 61247) [x86_64-linux]

There wasn’t much on the error but I checked the Ruby installation and ruby-devel package wasn’t installed by default. That’s odd since I choose to install the development components on the workstation.

Not a problem, I simply ran the yum utility as root through a sudoer user to install the ruby-devel package:

yum install -y ruby-devel

You should see a successful installation log like:

As I suspected, it fixed the problem immediately when I ran gem utility to install the mongo gem. The syntax to install the mongo gem is:

gem install mongo

The console output should be:

Building native extensions.  This could take a while...
Successfully installed bson-4.3.0
Fetching: mongo-2.5.3.gem (100%)
Successfully installed mongo-2.5.3
Parsing documentation for bson-4.3.0
Installing ri documentation for bson-4.3.0
Parsing documentation for mongo-2.5.3
Installing ri documentation for mongo-2.5.3
Done installing documentation for bson, mongo after 3 seconds
2 gems installed

You can now write and run a Ruby test MongoDB connection program. Here’s a basic MongoDBTest.rb Ruby file:

#!/usr/bin/ruby
 
# Require libraries.
require 'rubygems'
require 'mongo'
 
# Create a new connection to MongoDB.
$client = Mongo::Client.new(['localhost'])
 
puts 'Connected to MongoDB'
puts '===================='
puts 'Database Names:'
puts '---------------'
$client.database_names.each{|name| puts name}

After you create the MongoDBTest.rb file, you need to change its permissions with the chmod utility as follows:

chmod 755 MongoDBTest.rb

Then, you can run it as follows from the directory where you created the file:

./MongoDBTest.rb

Unless you’ve added something to the base MongoDB instance, it should print:

Connected to MongoDB
====================
Database Names:
---------------
admin
local

As always, I hope this helps somebody looking for a straightforward example and solution.

Written by maclochlainn

May 17th, 2018 at 2:00 pm

MongoDB on Fedora 27

without comments

I was very pleased to see MongoDB 3.4 in the repo for Fedora 27; however, I was quite frankly severely disappointed by the lack of concrete installation steps in the MongoDB in Action, Second Edition. The installation is straightforward as long as you remember that you don’t simply install a mongodb package. You need to install the mongodb and mongodb-server packages as well as some dependents.

As the root user, you can use yum to install them like this:

yum install -y mongo*

After installing the correct packages, you can start the MongoDB Daemon as a service using the root account or a sudoer account (if you get warning messages, you need to create a mongod file):

service mongod start

Finally, you can connect to the MongoDB client, like so:

mongo

Inside the mongo shell, you can check the MongoDB version with the following command:

db.version()

It should print:

3.4.11

Or, you can check the statistics of a new empty instance:

db.stats()

A fresh installation of MongoDB 3.4.11 on Fedora 27 should return:

{
        "db" : "test",
        "collections" : 0,
        "views" : 0,
        "objects" : 0,
        "avgObjSize" : 0,
        "dataSize" : 0,
        "storageSize" : 0,
        "numExtents" : 0,
        "indexes" : 0,
        "indexSize" : 0,
        "fileSize" : 0,
        "ok" : 1
}

You can insert data into MongoDB by creating a database, which is simply a file. You use an existing database or file by using the use command. If the database or file doesn’t exist already, the use command creates the database.

use videodb

You can create a collection or table with the insert function. The following creates an item collection and adds two JSON objects to the item collection.

db.item.insert({item:"Star Wars: A New Hope"})

It returns:

WriteResult({ "nInserted" : 1 })

You can create or add to an item collection or table with the same insert function call. You simply enclose the list of collection elements in the square brackets of a JavaScript array or list. The following inserts the second and third Star Wars films:

db.item.insert([{item:"Star Wars: The Empire Strikes Back"},{item:"Star Wars: Return of the Jedi"}])

It returns:

BulkWriteResult({
        "writeErrors" : [ ],
        "writeConcernErrors" : [ ],
        "nInserted" : 2,
        "nUpserted" : 0,
        "nMatched" : 0,
        "nModified" : 0,
        "nRemoved" : 0,
        "upserted" : [ ]

You can query the collection with the find function, like:

db.item.find()

It returns:

{ "_id" : ObjectId("5b02732435b861850bc51ef1"), "item" : "Star Wars: A New Hope" }
{ "_id" : ObjectId("5b02734635b861850bc51ef2"), "item" : "Star Wars: The Empire Strikes Back" }
{ "_id" : ObjectId("5b02734635b861850bc51ef3"), "item" : "Star Wars: Return of the Jedi" }

You can write large JavaScript files for bulk inserts. For example, the following users.js file:

db.users.insert(
[
  { contact_account: "CA_20170321_0001"
  , first_name: "Jonathan"
  , middle_name: "Eoin"
  , last_name: "MacGregor"
  , addresses:
    {
      street_address: ["1111 Broadway","Suite 101"]
    , city: "Oakland"
    , state: "CA"
    , zip: "94607" 
    }
  }
, { contact_account: "CA_20170328_0001"
  , first_name: "Remington"
  , middle_name: "Alain" 
  , last_name: "Dennison"
  , addresses:
    {
      street_address: ["2222 Broadway","Suite 121"]
    , city: "Oakland"
    , state: "CA"
    , zip: "94607" 
    }
  }
])

You can call the file with the load command from the interactive MongoDB command line:

load("/home/student/Code/mongodb/users.js")

You can query the results after you load the collection elements in the users collection with the following command:

db.users.find()

It returns:

{ "_id" : ObjectId("5b0270d535b861850bc51eef"), "contact_account" : "CA_20170321_0001", "first_name" : "Jonathan", "middle_name" : "Eoin", "last_name" : "MacGregor", "addresses" : { "street_address" : [ "1111 Broadway", "Suite 101" ], "city" : "Oakland", "state" : "CA", "zip" : "94607" } }
{ "_id" : ObjectId("5b0270d535b861850bc51ef0"), "contact_account" : "CA_20170328_0001", "first_name" : "Remington", "middle_name" : "Alain", "last_name" : "Dennison", "addresses" : { "street_address" : [ "2222 Broadway", "Suite 121" ], "city" : "Oakland", "state" : "CA", "zip" : "94607" } }

In both cases, the item and user collections add a unique identifier. The unique identifier is much like a surrogate key in a relational database. That’s why you should always define a unique natural key in the definition of your collection.

As always, I hope this helps.

Written by maclochlainn

May 16th, 2018 at 6:05 pm

How to install MongoDB

without comments

This post shows the yum command to install the MongoDB packages on Linux. More on setup and use will follow.

You install the MongoDB package with the following yum command:

yum install -y mongodb

You should see the following log file, which may also show a missing mirrored site:

Loaded plugins: langpacks, refresh-packagekit
cassandra/signature                                         |  819 B  00:00     
cassandra/signature                                         | 2.9 kB  00:00 !!! 
mysql-connectors-community                                  | 2.5 kB  00:00     
mysql-tools-community                                       | 2.5 kB  00:00     
mysql56-community                                           | 2.5 kB  00:00     
updates/20/x86_64/metalink                                  | 2.6 kB  00:00     
Resolving Dependencies
--> Running transaction check
---> Package mongodb.x86_64 0:2.4.6-1.fc20 will be installed
--> Processing Dependency: v8 for package: mongodb-2.4.6-1.fc20.x86_64
--> Processing Dependency: libv8.so.3()(64bit) for package: mongodb-2.4.6-1.fc20.x86_64
--> Processing Dependency: libtcmalloc.so.4()(64bit) for package: mongodb-2.4.6-1.fc20.x86_64
--> Processing Dependency: libboost_program_options.so.1.54.0()(64bit) for package: mongodb-2.4.6-1.fc20.x86_64
--> Processing Dependency: libboost_iostreams.so.1.54.0()(64bit) for package: mongodb-2.4.6-1.fc20.x86_64
--> Processing Dependency: libboost_filesystem.so.1.54.0()(64bit) for package: mongodb-2.4.6-1.fc20.x86_64
--> Running transaction check
---> Package boost-filesystem.x86_64 0:1.54.0-12.fc20 will be installed
---> Package boost-iostreams.x86_64 0:1.54.0-12.fc20 will be installed
---> Package boost-program-options.x86_64 0:1.54.0-12.fc20 will be installed
---> Package gperftools-libs.x86_64 0:2.1-4.fc20 will be installed
---> Package v8.x86_64 1:3.14.5.10-18.fc20 will be installed
--> Finished Dependency Resolution
 
Dependencies Resolved
 
================================================================================
 Package                   Arch       Version                 Repository   Size
================================================================================
Installing:
 mongodb                   x86_64     2.4.6-1.fc20            fedora       30 M
Installing for dependencies:
 boost-filesystem          x86_64     1.54.0-12.fc20          updates      66 k
 boost-iostreams           x86_64     1.54.0-12.fc20          updates      59 k
 boost-program-options     x86_64     1.54.0-12.fc20          updates     147 k
 gperftools-libs           x86_64     2.1-4.fc20              updates     266 k
 v8                        x86_64     1:3.14.5.10-18.fc20     updates     3.0 M
 
Transaction Summary
================================================================================
Install  1 Package (+5 Dependent packages)
 
Total download size: 34 M
Installed size: 101 M
Downloading packages:
(1/6): boost-iostreams-1.54.0-12.fc20.x86_64.rpm            |  59 kB  00:00     
(2/6): boost-filesystem-1.54.0-12.fc20.x86_64.rpm           |  66 kB  00:00     
(3/6): boost-program-options-1.54.0-12.fc20.x86_64.rpm      | 147 kB  00:00     
(4/6): gperftools-libs-2.1-4.fc20.x86_64.rpm                | 266 kB  00:00     
(5/6): v8-3.14.5.10-18.fc20.x86_64.rpm                      | 3.0 MB  00:00     
(6/6): mongodb-2.4.6-1.fc20.x86_64.rpm                      |  30 MB  00:04     
--------------------------------------------------------------------------------
Total                                              7.6 MB/s |  34 MB  00:04     
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction (shutdown inhibited)
  Installing : 1:v8-3.14.5.10-18.fc20.x86_64                                1/6 
  Installing : boost-program-options-1.54.0-12.fc20.x86_64                  2/6 
  Installing : gperftools-libs-2.1-4.fc20.x86_64                            3/6 
  Installing : boost-filesystem-1.54.0-12.fc20.x86_64                       4/6 
  Installing : boost-iostreams-1.54.0-12.fc20.x86_64                        5/6 
  Installing : mongodb-2.4.6-1.fc20.x86_64                                  6/6 
  Verifying  : boost-iostreams-1.54.0-12.fc20.x86_64                        1/6 
  Verifying  : boost-filesystem-1.54.0-12.fc20.x86_64                       2/6 
  Verifying  : gperftools-libs-2.1-4.fc20.x86_64                            3/6 
  Verifying  : mongodb-2.4.6-1.fc20.x86_64                                  4/6 
  Verifying  : boost-program-options-1.54.0-12.fc20.x86_64                  5/6 
  Verifying  : 1:v8-3.14.5.10-18.fc20.x86_64                                6/6 
 
Installed:
  mongodb.x86_64 0:2.4.6-1.fc20                                                 
 
Dependency Installed:
  boost-filesystem.x86_64 0:1.54.0-12.fc20                                      
  boost-iostreams.x86_64 0:1.54.0-12.fc20                                       
  boost-program-options.x86_64 0:1.54.0-12.fc20                                 
  gperftools-libs.x86_64 0:2.1-4.fc20                                           
  v8.x86_64 1:3.14.5.10-18.fc20                                                 
 
Complete!

Hope this helps those looking for the command.

Written by maclochlainn

September 27th, 2017 at 10:16 pm