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:
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:
Projection Syntax:
You can not mix 0 and 1 unless there is a _id
field that you want to exclude, like this:
Or:
Exception:
part-6 is here. More about Array Operators, Projection, and many more interesting topics.
Thanks for reading, any correction or recommendation is welcome.