MongoDB Basic Shell Commands (part-5)

MongoDB Basic Shell Commands (part-5)

MongoDB Basic Shell Commands (part-4)

Array Operators

$push

  • Allows us to add an element to an array.
  • Turns a field into an array field if it was previously a different type.

The following command updates one document in the grades collection where the student_id is 250, and the class_id field is 339 , by adding a document element to the "scores" array.

db.grades.updateOne({ "student_id": 250, "class_id": 339 },
                    { "$push": { "scores": { "type": "extra credit",
                                             "score": 100 }
                                }
                     })

Let us switch to one of the sample databases, use sample_airbnb, there is a collection: listingsAndReviews. Each Airbnb listing has a field with an array of available amenities. Let us issue a query for one of the entries where Shampoo is one of the amenities.

db.listingsAndReviews.findOne({"amenities": "Shampoo"})

The resulting document may look like this (notice amenities include shampoo):

{
        "_id" : "10057826",
        "listing_url" : "https://www.airbnb.com/rooms/10057826",
        "name" : "Deluxe Loft Suite",
        "summary" : "Loft Suite Deluxe...",
        "space" : "This loft unit ...",
        "description" : "Loft Suite Deluxe...",
        "neighborhood_overview" : "Greenpoint ...",
        "notes" : "",
        "transit" : "",
        "access" : "Guest will have access to common terraces...",
        "interaction" : "",
        "house_rules" : "Guest must leave a copy of credit card with...",
        "property_type" : "Apartment",
        "room_type" : "Entire home/apt",
        "bed_type" : "Real Bed",
        "minimum_nights" : "3",
        "maximum_nights" : "1125",
        "cancellation_policy" : "strict_14_with_grace_period",
        "last_scraped" : ISODate("2019-03-07T05:00:00Z"),
        "calendar_last_scraped" : ISODate("2019-03-07T05:00:00Z"),
        "first_review" : ISODate("2016-01-03T05:00:00Z"),
        "last_review" : ISODate("2018-02-18T05:00:00Z"),
        "accommodates" : 4,
        "bedrooms" : 0,
        "beds" : 2,
        "number_of_reviews" : 5,
        "bathrooms" : NumberDecimal("1.0"),
        "amenities" : [
                "TV",
                "Cable TV",
                "Internet",
                "Wifi",
                "Air conditioning",
                "Kitchen",
                "Doorman",
                "Gym",
                "Elevator",
                "Heating",
                "Family/kid friendly",
                "Washer",
                "Dryer",
                "Smoke detector",
                "Carbon monoxide detector",
                "First aid kit",
                "Fire extinguisher",
                "Essentials",
                "Shampoo",
                "24-hour check-in",
                "Hangers",
                "Hair dryer",
                "Iron"
        ],
        "price" : NumberDecimal("205.00"),
        "extra_people" : NumberDecimal("0.00"),
        "guests_included" : NumberDecimal("1"),
        "images" : {...},
        "host" : {...},
        "address" : {...},
        "availability" : {...},
        "review_scores" : {...},
        "reviews" : [...]
}

Though our query does not look like we are looking for an array field, it still finds the required documents. If we issue a query like this:

db.listingsAndReviews.findOne({"amenities": ["Shampoo"]}), this will return no documents because it will search for an exact field where the value is an array with only one element Shampoo.

Order of the elements matters inside an array.

$all and $size

$all operator will return all the documents where the array field contains at least all those elements, irrespective of their order inside the array. Now look at the following query:

db.listingsAndReviews.find({ "amenities": {
                                  "$all": [ "Internet", "Wifi",  "Kitchen",
                                           "Heating", "Family/kid friendly",
                                           "Washer", "Dryer", "Essentials",
                                           "Shampoo", "Hangers",
                                           "Hair dryer", "Iron",
                                           "Laptop friendly workspace" ]
                                         }
                            }).pretty()

$size operator will restrict the size of the array field. The array must contain exactly that many elements satisfying other restrictions on it. Let us have a look at $size in action.

db.listingsAndReviews.find({ "amenities": {
                                  "$size": 20,
                                  "$all": [ "Internet", "Wifi",  "Kitchen",
                                           "Heating", "Family/kid friendly",
                                           "Washer", "Dryer", "Essentials",
                                           "Shampoo", "Hangers",
                                           "Hair dryer", "Iron",
                                           "Laptop friendly workspace" ]
                                         }
                            }).pretty()

The following query will return all listings that have "Free parking on premises", "Air conditioning", and "Wifi" as part of their amenities, and have at least 2 bedrooms in the sample_airbnb.listingsAndReviews collection:

db.listingsAndReviews.find(
  { "amenities":
      { "$all": [ "Free parking on premises", "Wifi", "Air
        conditioning" ] }, "bedrooms": { "$gte":  2 } } ).pretty()

So to summarize:

image.png

Array Operators and Projection

We often handle big documents where we are not interested in all the fields it contains, we only want to return some of the fields that we are interested in at the moment. How can we return documents this way? Projection is the answer. It is the second argument of the find() method. Let us see how to use it. The following query will find all documents with exactly 20 amenities which include all the amenities listed in the query array, and display their price and address, excluding all other fields except _id:

db.listingsAndReviews.find({ "amenities":
        { "$size": 20, "$all": [ "Internet", "Wifi",  "Kitchen", "Heating",
                                 "Family/kid friendly", "Washer", "Dryer",
                                 "Essentials", "Shampoo", "Hangers",
                                 "Hair dryer", "Iron",
                                 "Laptop friendly workspace" ] } },
                            {"price": 1, "address": 1}).pretty()

The following query finds all documents that have Wifi as one of the amenities only include price and address in the resulting cursor:

db.listingsAndReviews.find({ "amenities": "Wifi" },
                           { "price": 1, "address": 1, "_id": 0 }).pretty()

Let us look at their rules at a glance:

image.png

Projection Syntax: You can not mix 0 and 1 unless there is a _id field that you want to exclude, like this:

image.png Or:

image.png

Exception:

image.png

part-6 is here. More about Array Operators, Projection, and many more interesting topics.

Thanks for reading, any correction or recommendation is welcome.