MongoDB 2.4 Fixed Length Arrays & Release Candidate 2
PublishedThe MongoDB Experimental Plans are updated and running MongoDB 2.4 Release Candidate 2. One of the new features in MongoDB 2.4 is fixed length arrays. It will make schema design a little easier.
Fixed Length Array in MongoDB
With MongoDB 2.4, one of the cool features is atomic fixed length arrays. To use, combine the $push
and $slice
functionality. Previously, to have fixed length arrays, you would need to run two separate commands: $find
and inplace $set
of the entire array.
Now, you can create fixed length arrays with the {$push: {"field_name": {$each: ["array_of_elements"], $slice: -4}}}
where field_name is the attribute on the document, and slice is the length of the document (always negative or 0). Essentially, the example above will:
- Push to the right side of the array
- Keep the 4 elements on the right side of the array
An Example
We are going to record the last 5 readings for a river gauge:
> doc = db.gauges.insert({_id: ObjectId("513cc4c663c0a2303e1ec093"), name: "Niagra River"})
> db.gauges.update({ _id: ObjectId("513cc4c663c0a2303e1ec093")}, {$push: {lastest_gauge_readings: {$each: [{cubic_meter_second: 5796, at: new Date()}], $slice: -5}}})
> db.gauges.find()[0]
{
"_id" : ObjectId("513cc4c663c0a2303e1ec093"),
"lastest_gauge_readings" : [
{
"cubic_meter_second" : 5796,
"at" : ISODate("2013-03-10T17:46:00.810Z")
}
],
"name" : "Niagra River"
}
As you can see the $push
syntax has changed. It is using a more verbose, more functional syntax. In the example above, with $push
, we are adding each element in the $each
array to the right side of the index. Then, with $slice
, we are keeping the 5 right most elements. Below, we will run the following 5 more times with random values:
> db.gauges.update({ _id: ObjectId("513cc4c663c0a2303e1ec093")}, {$push: {lastest_gauge_readings: {$each: [{cubic_meter_second: 5800, at: new Date()}], $slice: -5}}})
> db.gauges.update({ _id: ObjectId("513cc4c663c0a2303e1ec093")}, {$push: {lastest_gauge_readings: {$each: [{cubic_meter_second: 5960, at: new Date()}], $slice: -5}}})
> db.gauges.update({ _id: ObjectId("513cc4c663c0a2303e1ec093")}, {$push: {lastest_gauge_readings: {$each: [{cubic_meter_second: 6000, at: new Date()}], $slice: -5}}})
> db.gauges.update({ _id: ObjectId("513cc4c663c0a2303e1ec093")}, {$push: {lastest_gauge_readings: {$each: [{cubic_meter_second: 6200, at: new Date()}], $slice: -5}}})
> db.gauges.update({ _id: ObjectId("513cc4c663c0a2303e1ec093")}, {$push: {lastest_gauge_readings: {$each: [{cubic_meter_second: 6300, at: new Date()}], $slice: -5}}})
> db.gauges.find()[0]
{
"_id" : ObjectId("513cc4c663c0a2303e1ec093"),
"lastest_gauge_readings" : [
{
"cubic_meter_second" : 5800,
"at" : ISODate("2013-03-10T17:48:31.508Z")
},
{
"cubic_meter_second" : 5960,
"at" : ISODate("2013-03-10T17:48:37.268Z")
},
{
"cubic_meter_second" : 6000,
"at" : ISODate("2013-03-10T17:48:42.308Z")
},
{
"cubic_meter_second" : 6200,
"at" : ISODate("2013-03-10T17:48:45.917Z")
},
{
"cubic_meter_second" : 6300,
"at" : ISODate("2013-03-10T17:48:49.247Z")
}
],
"name" : "Niagra River"
}
The $slice
operator keeps n-right most elements of the array.
Sorted Fixed Length Arrays in MongoDB
If you like Redis’s zscore
functionality, and want to bring it into MongoDB. The latest MongoDB 2.4 is bringing the sorted arrays functionality to MongoDB with the added $push
features.
Common scenarios for this are like: - Content management system - related posts, top n refererring products - E-commerce storefront - top n referring products - Social Aggregation - top n retweeted status updates Sorted arrays are a nice way to cache values instead of using a sort on another query. Try to use these instead of sort queries against entire collections. We will continue to use our river gauge example on the Niagra River:
> db.gauges.update({ _id: ObjectId("513cc4c663c0a2303e1ec093")}, {$push: {highest_gauge_readings: {$each: [{cubic_meter_second: 5796, at: new Date()}], $sort: {cubic_meter_second: 1}, $slice: -5}}})
Above, we are using $sort
to specify a key(s) to sort from, then using $slice
to keep the last 5. We will run 5 more pushes to the document:
> db.gauges.update({ _id: ObjectId("513cc4c663c0a2303e1ec093")}, {$push: {highest_gauge_readings: {$each: [{cubic_meter_second: 5796, at: new Date()}], $sort: {cubic_meter_second: 1}, $slice: -5}}})
> db.gauges.update({ _id: ObjectId("513cc4c663c0a2303e1ec093")}, {$push: {highest_gauge_readings: {$each: [{cubic_meter_second: 5900, at: new Date()}], $sort: {cubic_meter_second: 1}, $slice: -5}}})
> db.gauges.update({ _id: ObjectId("513cc4c663c0a2303e1ec093")}, {$push: {highest_gauge_readings: {$each: [{cubic_meter_second: 5600, at: new Date()}], $sort: {cubic_meter_second: 1}, $slice: -5}}})
> db.gauges.update({ _id: ObjectId("513cc4c663c0a2303e1ec093")}, {$push: {highest_gauge_readings: {$each: [{cubic_meter_second: 2500, at: new Date()}], $sort: {cubic_meter_second: 1}, $slice: -5}}})
> db.gauges.update({ _id: ObjectId("513cc4c663c0a2303e1ec093")}, {$push: {highest_gauge_readings: {$each: [{cubic_meter_second: 7500, at: new Date()}], $sort: {cubic_meter_second: 1}, $slice: -5}}})
> db.gauges.find()[0]
{
"_id" : ObjectId("513cc4c663c0a2303e1ec093"),
"highest_gauge_readings" : [
{
"cubic_meter_second" : 2500,
"at" : ISODate("2013-03-10T17:59:59.315Z")
},
{
"cubic_meter_second" : 5600,
"at" : ISODate("2013-03-10T17:59:51.695Z")
},
{
"cubic_meter_second" : 5796,
"at" : ISODate("2013-03-10T17:59:11.096Z")
},
{
"cubic_meter_second" : 5900,
"at" : ISODate("2013-03-10T17:59:46.215Z")
},
{
"cubic_meter_second" : 7500,
"at" : ISODate("2013-03-10T18:00:05.345Z")
}
],
"name" : "Niagra River"
}
Other Features
If you are looking for a comprehensive list of MongoDB features, take a look at MongoDB 2.4 Release Notes. To begin using a Sandbox database with MongoHQ, Sign Up and create a Sandbox database. To upgrade any paid databases to 2.4.0-rc2, please send an email to support@mongohq.com with your database name.