-
Type: Bug
-
Resolution: Won't Do
-
Priority: Major - P3
-
Affects Version/s: None
-
Labels:None
Description
One of the freelancer writers that is writing an article for the SEO-Hygiene initiative (Content Marketing & Growth Teams) got stuck on writing some sample code examples with Node.js driver for the example of using MongoDB mapReduce.
My team, Developer Advocate team, notice a couple things on the reference documentation that needs to be more clear:
- out needs to be an object: https://mongodb.github.io/node-mongodb-native/3.6/api/Collection.html
- in JS in general array.sum does not look correct, it should be array.reduce
For Context the thread of the email of the freelancer writer:
At any rate, back to the issues with mapReduce; I attempted to run the following code:
"""
await collection.mapReduce(
function() {
emit(1, this.itemsTotal)
},
function(key, values) {
return Array.sum(values)
}
)
"""
According to the Node driver's .d.ts files, this is valid usage. However, I got the error:
"""
TypeError: Cannot read property 'out' of undefined
at Collection.mapReduce
"""
So, looking back at the docs page, I saw that there was a string assigned to "out":
"""
await collection.mapReduce(
function() {
emit(1, this.itemsTotal)
},
function(key, values) {
return Array.sum(values)
},
{
out: "Test"
}
)
"""
Not only did I get errors from typescript saying that "out" needed to be an object, I got the same error as before.
However, with some searching online, I found that you're able to change the last config object to:
"""
{
out: { inline: 1 }
}
"""
Once I did this, I got an array of values, without commas, not combined in any way, returned to the console.
Code:
"""
await collection.mapReduce(
function() {
emit(1, this.itemsTotal)
},
function(key, values) {
return Array.sum(values);
},
{
out: { inline: 1 }
}
)
"""
Output (shortened):
"""
[{"_id":1,"value":"NumberDecimal(\"1863.46\")NumberDecimal(\"798.25\")NumberDecimal(\"756.90\")NumberDecimal(\"758.22\")NumberDecimal(\"233.58\")NumberDecimal(\"122.05\")NumberDecimal(\"1628.90\")NumberDecimal(\"355.79\")NumberDecimal(\"1200.78\")NumberDecimal(\"719.72\")
"""
Not knowing how Array.sum works (it's not valid JS, but it's documented as the way to combine an array of numbers from the docs page), I decided to use `values.reduce` to manually add the numbers together:
"""
await collection.mapReduce(
function() {
emit(1, this.itemsTotal)
},
function(key, values) {
return values.reduce((p: number, c: any) => p + c, 0)
},
{
out: { inline: 1 }
}
)
"""
However, I ended up just getting `0` as a string appended at the start
"""
[{"_id":1,"value":"0NumberDecimal(\"1863.46\")NumberDecimal(\"798.25\")NumberDecimal(\"756.90\")NumberDecimal(\"758.22\")NumberDecimal(\"233.58\")
"""
I then decided to try and get the value of `NumberDecimal`.
I tried using `parseInt` on `c`, which left me with `0` as a final result. I assume this is because `parseInt(Object)` is `NaN`
The only way I was able to get the results of the numbers combined was the following code:
"""
await collection.mapReduce(
function() {
emit(1, this.itemsTotal)
},
function(key, values) {
return values.reduce((p: number, c: any) => p + Number(JSON.parse(JSON.stringify(c))["$numberDecimal"], 0)
},
{
out: { inline: 1 }
}
)
"""
However, this seems like an obvious anti-pattern and I wouldn't feel comfortable putting this as official docs that I wrote.
Just to make sure this wasn't a bug in the NodeJS driver, I attempted to use the Mongo Shell:
"""
use("sample_supplies");
db.sales.mapReduce(
function() {
emit(1, this.itemsTotal)
},
function(key, values) {
return values.reduce((p, c) => p + c, 0)
},
{
out: { inline: 1 }
}
)
"""
And ran into the same issues as before (I tried all of the code variations I outlined for NodeJS as well with the same results)