How to: MongoDB and Mongoose - Hives/makers-weather-station GitHub Wiki

Mongo DB

Why NoSql Db

  • works with a document structure (not table structure)

  • more flexible to changing the structure of the db

  • more flexible to adding new data types or not filling in an existing field

  • they implement relationships differently

  • not great with complex relationships

    • with NoSql we are not grouping related pieces of data in individual tables anymore

    • instead we have a Json with key = value pairs

      • we use document format
      • we have embedded objects to represent data
    • we can organize data into different documents - and can link them together through using references, but in that situation maybe use a SQL db. For NoSql design use the document embedded objects format

    • if we have a 1 to many relationship (user - posts), a single user generating a lot of content, it is much easier to map using mongo db

    • while MongoDb is somewhat weaker on the relationship front, it is scalable, it is not getting slower as you add data, and it can actually make the computer run out of memory

    • Sql is like calling a building vertically

    • NoSql (smaller chunks of data) you scale horizontally - a distributed system

CRUD operations \w SHELL

  • use mongod command to start the mongo server
  • go in a new terminal to tap int he mongo shell

Check existing databases

show dbs

CREATE

Create DB
use <name_of_database>

For database to be listed in show dbs, it must have some content

Check in which DB you are

db

Create record
Insert one record db.collection.insertOne({ <object> })

  • DB is the current database
  • Collection is the name of the collection. If it does not exist, it will be created by this command
  • insertOne is the mongo command to add one record to the document
  • object is the js object we are putting in the db

Example:

db.weather.insertOne({
  temperature: 5.0,
  pressure: 1039,
  humidity: 10%
})

Insert many
db.collection_name.insertMany([ {object1} ,{object2}, ... ],)

Read

db.weather.find()//retrieve all data
db.weather.find({condition})

Example:

  • find weather object with temperature greater than 5
db.weather.find(
  { temperature: {$gt: 5}}, //query criteria - filter
  { name: 1, address: 1} //projection: what fields to return
}).limit(10) //only 10 items

// RESULTS:

> db.weather.find({temperature: {$gt: 5}}

{ "_id" : ObjectId("5cd9cfbb0c88ac38b37c0d36"), "temperature" : 10, "pressure" : 1039, "humidity" : "10%" }

> db.weather.find({temperature: {$lt: 10}})

{ "_id" : ObjectId("5cd9cf970c88ac38b37c0d35"), "temperature" : 5, "pressure" : 1039, "humidity" : "10%" }

Query operator:
$gt is a query operator

Find more here: https://docs.mongodb.com/manual/reference/operator/query/

Example of matchers we might use:
$eq 5 => equal to 5
$gte 5 => greater than or equal to 5
$in => matches values specified in an array
$lt => less than
$lte => less than or equal to
$ne => not equal

Projection: { name: 1, address: 0}

  • 1 means true, 0 means false
  • identifies what fields we want returned
  • it is optional

Example:

> db.weather.find({temperature: {$lt: 10}}, {temperature:1, pressure:1})

{ "_id" : ObjectId("5cd9cf970c88ac38b37c0d35"), "temperature" : 5, "pressure" : 1039 }

> db.weather.find({temperature: {$lt: 10}}, {temperature:1})
{ "_id" : ObjectId("5cd9cf970c88ac38b37c0d35"), "temperature" : 5 }

Limit

  • limits number of records retrieved

Update

db.weather.updateOne({filter},{action})
db.weather.updateMany()
db.weather.ReplaceOne()

Example:

db.weather.updateOne(
  {pressure: {$eq: 1039}}, /.which record to replace
  {$set: {pressure: 1037}} /.replace with this
  )

//Result:
{ "acknowledged" : true, "matchedCount" : 2, "modifiedCount" : 2 }

> db.weather.find()

//Result:
{ "_id" : ObjectId("5cd9cf970c88ac38b37c0d35"), "temperature" : 5, "pressure" : 1037, "humidity" : "10%" }
{ "_id" : ObjectId("5cd9cfbb0c88ac38b37c0d36"), "temperature" : 10, "pressure" : 1037, "humidity" : "10%" }

Delete

db.weather.deleteOne({ <filter> })
db.weather.deleteMany({ <filter> })

Example:

db.weather.deleteOne({temperature: 5})

Bulk Write

  • can user insertMany()
db.weather.bulkWrite([
  {
    insertOne: {},
    insertOne: {},
    updateOne: {},
    deleteOne: {},
    replaceOne: {}
  }
])

Relationships

  • if we have 2 documents

    • we have one called weather
    • have another one called users

Example:

Single document bellow:

One to Many relationship

db.weather.insert(
  {
    user_id: 1,
    devices:
    { "raspb1":
      {
        "_id" : ObjectId("5cd9cf970c88ac38b37c0d35"),
        "temperature" : 5,
        "pressure" : 1039
      },
      "raspb2":
      {
        "_id" : ObjectId("5cd9cf970c88ac38b37c0d35"),
        "temperature" : 5,
        "pressure" : 1039
      }
    }
  }
)

// Result
{
"_id" : ObjectId("5cd9dade0c88ac38b37c0d37"),
"user_id" : 1,
"devices" : {
  "raspb1" : { "_id" : ObjectId("5cd9cf970c88ac38b37c0d35"), "temperature" : 5, "pressure" : 1039 },
  "raspb2" : { "_id" : ObjectId("5cd9cf970c88ac38b37c0d35"), "temperature" : 5, "pressure" : 1039 }
  }
}

Mongoose

npm install mongoose --save

Add the following to app.js:

Connect to DB

const mongoose = require('mongoose')

mongoose.connect('mongodb://localhost:27017/makers_weather_project', {
  useNewUrlParser: true
});

Insert data

  • create a new schema first
  • that's the structure of data we will save to the db
const weatherSchema = new mongoose.Schema ({
  temperature: Number,
  pressure: Number,
  humidity: number
})
  • create mongoose model
  • with 2 parameter
    • name of collection (singular)
    • schema the weather objects have to respec
const Weather = mongoose.model("weather_data", weatherSchema);
  • create document
const weather = new Weather({
  temperature: 10,
  pressure: 5,
  humidity: 10
})
  • save document
weather.save()

Add in bulk

  • takes 2 params = array of documents
  • callback function to handle errors
Weather.insertMany([weather2, weather3], function(err) {
  if (err) {
    console.log(err);
  } else {
    console.log('Success');
  }
});

Read data

  • we use the model to tap into the Weather collection
  • the callback handles the err and the result
  • if there is an error we flag it
  • if no error, we print result
Weather.find(function(err,result){
  if (err) {
   console.log(error)
  } else {
   console.log(result)
  }
})

To close a connection:

mongoose.connection.close()

Data validation

Check mongoose validation page: https://mongoosejs.com/docs/validation.html

  • change the schema as follows
  • prevents data that does not match the validation to be inserted in the database

Example:

const weatherSchema = new mongoose.Schema ({
  temperature: {
    type: Number,
    min: -100.0,
    max: 100.0,
    required: [true, "We need a temperature data..."]
  }
  pressure: Number,
  humidity: Number
})

Update / Delete

Update

  • mongoose documentation - has this method
  • what you need is the model
  • requires a condition to identify the element to update
  • requires a value to update to
Weather.updateOne({ temperature: 5 }, { temperature: 10 }, function(err) {
  if (err) {
    console.log(err);
  } else {
    console.log('Success');
  }
});

Delete

  • same as delete, without the extra params
Weather.deleteOne({ temperature: 5 }, function(err) {
  if (err) {
    console.log(err);
  } else {
    console.log('Delete success');
  }
});
  • Delete many
Weather.deleteMany({ temperature: 5 }, function(err) {
  if (err) {
    console.log(err);
  } else {
    console.log('Delete success');
  }
});

Establishing relationships between documents

  • Embed a user document in a weather document
  • can't call Weather.update with a new field
  • what we can do is add a new data entry with the extra field

Example:

const userSchema = new mongoose.Schema({
  first_name: String,
  last_name: String,
  email: String,
  password: String,
  weather: weatherSchema
});

weather: weatherSchema = tells mongoose we are embedding a weather document inside this property called weather, in the weather document

We can now create a new weather object:

const weather1 = new Weather({
  temperature: 10,
  pressure: 5,
  humidity: 10
});

weather.save();

Add the weather as an embedded document in a new user

const user = new User({
  first_name: 'John',
  last_name: 'Snow',
  email: '[email protected]',
  password: '1234',
  weather: weather1
});

user.save();

Update existing user with a weather object

  • create weather and save it
  • next...
Person.updateOne(
  { email: '[email protected]' },
  { weather: weather },
  function(err) {
    if (err) {
      console.log(err);
    }
  }
);

Full Example

2. Create schema
const weatherSchema = new mongoose.Schema({
temperature: {
type: Number,
min: -100.0,
max: 100.0,
required: [true, 'We need a temperature data...']
},
pressure: Number,
humidity: Number
});

2.1 User Schema
const userSchema = new mongoose.Schema({
first_name: String,
last_name: String,
email: String,
password: String,
weather: weatherSchema
});

3. Create Mongoose model
const Weather = mongoose.model('weather_data', weatherSchema);

3.1 Create User Mongoose model
const User = mongoose.model('User', userSchema);

4. Create document
const weather = new Weather({
temperature: 10,
pressure: 5,
humidity: 10
});

4.1 Save document
weather.save();

5 Create user document

const user = new User({
first_name: 'Daenerys',
last_name: 'Snow',
email: '[email protected]',
password: '1234',
weather: weather
});

5.1 Save user document
user.save();

6. Add in bulk
Weather.insertMany([weather2, weather3], function(err) {
if (err) {
console.log(err);
} else {
console.log('Success');
}
});

7. READ

Weather.find(function(err, result) {
if (err) {
console.log(error);
} else {
console.log(result); // print all data
result.forEach(function(wob) {
console.log(wob.temperature); //print out each temp
});
}
mongoose.connection.close();
});

8. Update

Weather.updateOne({ temperature: 10 }, { temperature: 11 }, function(err) {
if (err) {
console.log(err);
} else {
console.log('Success');
}
});

User.updateOne({ first_name: 'John' }, { weather: weather }, function(err) {
if (err) {
console.log(err);
}
});

9. Delete

Weather.deleteOne({ temperature: 11 }, function(err) {
if (err) {
console.log(err);
} else {
console.log('Delete success');
}
});

10. Delete many
⚠️ **GitHub.com Fallback** ⚠️