I cannot speak about MongoDB, but I can tell you about CouchDB. CouchDB can only be natively queried via a Map/Reduce View Engine. In fact, a great place to start is this section of the wiki.
A view contains a map function, and an optional reduce function. The typical language for writing these functions is JavaScript, but there is an Erlang option available, and it is possible to build a view engine in just about any other programming language.
The map function serves to build a data-set out of the documents in the database. The reduce function serves to aggregate that data-set. As such, the map function is run on every single document in the database once the view is created. (and first queried) After creation, that function only runs on a document that is either newly created, or is modified/deleted. As such, view indexes are built incrementally, not dynamically.
In the case of 1,000,000,000 values, CouchDB will not need to calculate the results of your query every single time it's requested. Instead, it will only report on the value of the view index it has stored, which itself only changes whenever a document is created/updated/deleted.
As far as writing Map/Reduce functions, a lot of that work is left up to the programmer, as there are no built-in map functions. (ie. it's not "automatic") However, there are a few native reduce functions (_sum
, _count
, _stats
) available.
Here's a simple example, we'll calculate the average height of some people.
// sample documents
{ "_id": "Dominic Barnes", "height": 64 }
{ "_id": "Some Tall Guy", "height": 75 }
{ "_id": "Some Short(er) Guy", "height": 58 }
// map function
function (doc) {
// first param is "key", which we do not need since `_id` is stored anyways
emit(null, doc.height);
}
// reduce function
_stats
The results of this view would look like this:
{
"rows": [
{
"key": null
"value": {
"sum": 197,
"count": 3,
"min": 58,
"max": 75,
"sumsqr": 13085
}
}
]
}
Calculating the average from here is as simple as dividing the sum by the count. If you want the average calculated within the view itself, you could check out this example.