Resolving MongoDB DBOef array using Mongo Native Query and working on resolved documents

My MongoDB collection consists of two main collections:

1) Maps

{
"_id" : ObjectId("542489232436657966204394"),
"fileName" : "importFile1.json",
"territories" : [ 
    {
        "$ref" : "territories",
        "$id" : ObjectId("5424892224366579662042e9")
    }, 
    {
        "$ref" : "territories",
        "$id" : ObjectId("5424892224366579662042ea")
    }
]
},

{
    "_id" : ObjectId("542489262436657966204398"),
    "fileName" : "importFile2.json",
    "territories" : [ 
        {
            "$ref" : "territories",
            "$id" : ObjectId("542489232436657966204395")
        }
    ],
    "uploadDate" : ISODate("2012-08-22T09:06:40.000Z")
}

      

2) Territories referenced by Map objects:

{
    "_id" : ObjectId("5424892224366579662042e9"),
    "name" : "Afghanistan",
    "area" : 653958
},
{
    "_id" : ObjectId("5424892224366579662042ea"),
    "name" : "Angola",
    "area" : 1252651
},
{
    "_id" : ObjectId("542489232436657966204395"),
    "name" : "Unknown",
    "area" : 0
}

      

My goal is to list each map with their cumulative area and number of territories. I am trying to execute the following query:

db.maps.aggregate(
    {'$unwind':'$territories'},
    {'$group':{
        '_id':'$fileName',
        'numberOf': {'$sum': '$territories.name'}, 
        'locatedArea':{'$sum':'$territories.area'}
        }
    })

      

However, the results show 0 for each of these values:

{
    "result" : [ 
        {
            "_id" : "importFile2.json",
            "numberOf" : 0,
            "locatedArea" : 0
        }, 
        {
            "_id" : "importFile1.json",
            "numberOf" : 0,
            "locatedArea" : 0
        }
    ],
    "ok" : 1
}

      

I probably did something wrong when trying to access Territory member variables (name and scope), but I couldn't find an example of such a case in the Mongo doc. the area is stored as an integer and the name as a string.

+3


source to share


1 answer


I probably did something wrong when I was trying to access the Territory member variables (name and scope), but I couldn't find an example of such a case in the Mongolian dock. the region is stored as an integer and the name as a string.

Yes, the field "territories"

has an array of database links and not the actual documents

. DBRefs

- objects that contain information with which we can locate the actual documents

.

In the above example, you can clearly see this, fire below mongo request:

db.maps.find({"_id":ObjectId("542489232436657966204394")}).forEach(function(do
c){print(doc.territories[0]);})

      

it will print the DBRef object, not the document itself:

o/p: DBRef("territories", ObjectId("5424892224366579662042e9"))

      

therefore '$sum': '$territories.name'

, '$sum': '$territories.area'

will show you "0" since there are no fields like name

or area

.

So, you need to resolve this doc link before doing something like $territories.name

To achieve what you want, you can use a function map()

as the aggregation and ancillary queries support Map-less and you already have a standalone document map

with links to it territories

.

Steps to Achieve:



a) get each map
b) resolve the `DBRef`.
c) calculate the total area, and the number of territories.
d) make and return the desired structure.

      

Mongolian shell script:

db.maps.find().map(function(doc) {
    var territory_refs = doc.territories.map(function(terr_ref) {
        refName = terr_ref.$ref;
        return terr_ref.$id;
    });
    var areaSum = 0;
    db.refName.find({
        "_id" : {
            $in : territory_refs
        }
    }).forEach(function(i) {
        areaSum += i.area;
    });
    return {
        "id" : doc.fileName,
        "noOfTerritories" : territory_refs.length,
        "areaSum" : areaSum
    };
})

      

o / p:

[
        {
                "id" : "importFile1.json",
                "noOfTerritories" : 2,
                "areaSum" : 1906609
        },
        {
                "id" : "importFile2.json",
                "noOfTerritories" : 1,
                "areaSum" : 0
        }
]

      

Map-Reduce

functions should not and cannot be used for DBRefs

server side resolution . See what the documentation has to say:

The map function shouldn't access the database for any reason.

The map function must be pure or have no effect outside the function (i.e. side effects).

The shrink function does not have to access the database, even to perform a read operation. The reduction function should not affect the external system.

Also, the function reduce

, even if used (which may never work anyway), will never be called for your problem, as the wrt "fileName"

or group "ObjectId"

will always only have one document in your dataset.

MongoDB will not call a decrement function on a key that only has a single value

+1


source







All Articles