CopyPastor

Detecting plagiarism made easy.

Score: 0.800625741481781; Reported for: String similarity Open both answers

Possible Plagiarism

Plagiarized on 2023-02-16
by rickhg12hs

Original Post

Original - Posted on 2014-05-14
by Neil Lunn



            
Present in both answers; Present only in the new answer; Present only in the old answer;

Here's another way to do it by using `"$reduce"`. Comments are in the aggregation pipeline. ```mongodb db.collection.aggregate([ { "$set": { // rewrite fruits "fruits": { "$reduce": { "input": "$fruits", "initialValue": [], "in": { "$let": { "vars": { // get fruit index in $$value : will be -1 if not there "idx": {"$indexOfArray": ["$$value.fruit", "$$this.fruit"]} }, "in": { "$cond": [ // is fruit not in $$value yet {"$eq": ["$$idx", -1]}, // new fruit so put in $$value and make "type" an array { "$concatArrays": [ "$$value", [{"$mergeObjects": ["$$this", {"type": ["$$this.type"]}]}] ] }, // fruit already in $$value, so map $$value with "type" update { "$map": { "input": "$$value", "as": "val", "in": { "$cond": [ // is this array element not the right fruit? {"$ne": ["$$val.fruit", "$$this.fruit"]}, // nope, leave the element as-is "$$val", // this element needs to be updated { "$mergeObjects": [ "$$val", { "type": { "$cond": [ // is this "type" already in array? {"$in": ["$$this.type", "$$val.type"]}, // yes, so leave it as-is "$$val.type", // this is a new "type", so add it to array {"$concatArrays": ["$$val.type", ["$$this.type"]]} ] } } ] } ] } } } ] } } } } } } } ]) ``` Try it on [mongoplayground.net](https://mongoplayground.net/p/QsO_1Y5Cnve "Click me!").
For your actual form, and therefore presuming that you actually know the possible values for "type" then you can do this with two [**`$group`**][1] stages and some use of the [**`$cond`**][2] operator:
<!-- language-all: lang-js -->
db.types.aggregate([ { "$group": { "_id": { "stat": "$stat", "type": "$type" }, "count": { "$sum": 1 } }}, { "$group": { "_id": "$_id.stat", "type1": { "$sum": { "$cond": [ { "$eq": [ "$_id.type", 1 ] }, "$count", 0 ]}}, "type2": { "$sum": { "$cond": [ { "$eq": [ "$_id.type", 2 ] }, "$count", 0 ]}}, "type3": { "$sum": { "$cond": [ { "$eq": [ "$_id.type", 3 ] }, "$count", 0 ]}} }} ])
Which gives exactly:
{ "_id" : "foobar", "type1" : 2, "type2" : 1, "type3" : 1 }

I actually prefer the more dynamic form with two [**`$group`**][1] stages though:

db.types.aggregate([ { "$group": { "_id": { "stat": "$stat", "type": "$type" }, "count": { "$sum": 1 } }}, { "$group": { "_id": "$_id.stat", "types": { "$push": { "type": "$_id.type", "count": "$count" }} }} ])
Not the same output but functional and flexible to the values:
{ "_id" : "foobar", "types" : [ { "type" : 3, "count" : 1 }, { "type" : 2, "count" : 1 }, { "type" : 1, "count" : 2 } ] }
Otherwise if you need the same output format but need the flexible fields then you can always use mapReduce, but it's not exactly the same output.
db.types.mapReduce( function () {
var obj = { };
var key = "type" + this.type; obj[key] = 1;
emit( this.stat, obj );
}, function (key,values) {
var obj = {};
values.forEach(function(value) { for ( var k in value ) { if ( !obj.hasOwnProperty(k) ) obj[k] = 0; obj[k]++; } });
return obj;
}, { "out": { "inline": 1 } } )
And in typical mapReduce style:
"results" : [ { "_id" : "foobar", "value" : { "type1" : 2, "type2" : 1, "type3" : 1 } } ],
But those are your options



[1]: http://docs.mongodb.org/manual/reference/operator/aggregation/group/ [2]: http://docs.mongodb.org/manual/reference/operator/aggregation/cond/

        
Present in both answers; Present only in the new answer; Present only in the old answer;