How can one smooth double arrays in mongoDB?

Some fields in my mongoDB docs look like this:

{ ... Countries: [["Spain", "France"]] ... } 

Or that:

 { ... Countries: [["Spain"],["Russia", "Egypt"]] ... } 

What I want to do is turn [["Spain", "France"]] into ["Spain", "France"] and [["Spain"],["Russia", "Egypt"]] into ["Spain", "Russia", "Egypt"] , similar to using the flatten method in Ruby.

Is there any way to smooth arrays in mongoDB? I need to smooth arrays in all documents in the entire collection, and not just in one document, if that matters, also the values ​​and their number in arrays vary between documents.

I also use Ruby as a driver for mongo, so a method using a Ruby driver will also be useful to me.

+5
source share
4 answers

Your country data is not in a good format, so you might consider converting it. This is a script to smooth the array in the Countries field and save the original documents that you can run in the mongo shell:

 function flattenArray(inArr) { var ret = []; inArr.forEach(function(arr) { if (arr.constructor.toString().indexOf("Array") > -1) { ret = ret.concat(flattenArray(arr)); } else { ret.push(arr); } }); return ret; } db.collection.find({ 'Countries': { '$exists': true } }).forEach(function(doc){ doc.Countries = flattenArray(doc.Countries); db.collection.save(doc); }); 
0
source

You need to perform an aggregation operation with two unwind stages and one group . The basic rule is that you unwind as many times as the level of nest depth. Here the nesting level is 2, so we unwind twice.

  collection.aggregate([ {$unwind => "$Countries"}, {$unwind => "$Countries"}, {$group => {"_id":"$_id","Countries":{$push => "$Countries"}}} ]) 

The first step of $unwind yields the result:

 { "_id" : ObjectId("54a32e0fc2eaf05fc77a5ea4"), "Countries" : [ "Spain", "France" ] } { "_id" : ObjectId("54a32e4ec2eaf05fc77a5ea5"), "Countries" : [ "Spain" ] } { "_id" : ObjectId("54a32e4ec2eaf05fc77a5ea5"), "Countries" : [ "Russia", "Egypt" ] } 

The second step of $unwind further aligns the Countries array:

 { "_id" : ObjectId("54a32e0fc2eaf05fc77a5ea4"), "Countries" : "Spain" } { "_id" : ObjectId("54a32e0fc2eaf05fc77a5ea4"), "Countries" : "France" } { "_id" : ObjectId("54a32e4ec2eaf05fc77a5ea5"), "Countries" : "Spain" } { "_id" : ObjectId("54a32e4ec2eaf05fc77a5ea5"), "Countries" : "Russia" } { "_id" : ObjectId("54a32e4ec2eaf05fc77a5ea5"), "Countries" : "Egypt" } 

Now the last step of $group groups records based on _id and accumulates country names in one array.

 { "_id" : ObjectId("54a32e4ec2eaf05fc77a5ea5"), "Countries" : [ "Spain", "Russia", "Egypt" ] } { "_id" : ObjectId("54a32e0fc2eaf05fc77a5ea4"), "Countries" : [ "Spain", "France" ] } 

If you want to save other fields in the document, you need to explicitly specify the names of fields other than the country field (field1, field2, etc.) using the $first operator. You can write / overwrite a collection by specifying the name of the collection at the $out stage.

 collection.aggregate([ {$unwind => "$Countries"}, {$unwind => "$Countries"}, {$group => {"_id":"$_id","Countries":{$push => "$Countries"}, "field1":{$first => "$field1"}}}, {$out => "collection"} ]) 

You need to explicitly specify the fields so that you do not get a redundant Countries field.

The $$ROOT variable can be used to store the entire document, but this will make the Countries field redundant. One outside the doc and one inside the doc .

 collection.aggregate([ {$unwind => "$Countries"}, {$unwind => "$Countries"}, {$group => {"_id":"$_id","Countries":{$push => "$Countries"}, "doc":{$first => "$$ROOT"}}}, {$out => "collection"} ]) 
+4
source

Try the following:

 db.test2.aggregate([ {"$unwind" : "$Countries"}, {"$unwind" : "$Countries"}, {$group : { _id : '$_id', Countries: { $addToSet: "$Countries" }}}, ]).result 
+3
source

In Mongo 3.4+, you can use $reduce to smooth 2d arrays.

 db.collection.aggregate( [ { $project: { "countries": { $reduce: { input: '$Countries', initialValue: [], in: {$concatArrays: ['$$value', '$$this']} } } } } ] ) 

Docs: https://docs.mongodb.com/manual/reference/operator/aggregation/reduce/

0
source

Source: https://habr.com/ru/post/1210231/


All Articles