mongodbhashmapmongodb-queryaggregation-framework

How to get data from mongoDB like a HashMap(Key value Pair)


Here are the records in my mongodb

{
    "_id": "5a65a047992e3c2572f74102",
    "_class": "com.vuelogix.location.model.LocationModel",
    "type": "Feature",
    "properties": {
        "address": "Purna to Loha Rd, Maharashtra 431511, India",
        "device_id": 23613,
        "last_updated": "2018-01-22T08:26:47.237Z"
    },
    "geometry": {
        "_class": "com.vuelogix.location.model.geojson.geometry.Point",
        "coordinates": [77.065659, 19.145168],
        "type": "Point"
    }
},

{
    "_id": "5a65ae1e992e3c2572f74114",
    "_class": "com.vuelogix.location.model.LocationModel",
    "type": "Feature",
    "properties": {
        "address": "Taranagar - Churu Rd, Chalkoi Baneerotan, Rajasthan 331001, India",
        "device_id": 23658,
        "last_updated": "2018-01-22T09:25:50.893Z"
    },
    "geometry": {
        "_class": "com.vuelogix.location.model.geojson.geometry.Point",
        "coordinates": [74.956284, 28.497661],
        "type": "Point"
    }
}

I want to get it as a key value pair: key should be "properties.device_id" and value entire record.

Like this

[23613] => {
    "_id": "5a65a047992e3c2572f74102",
    "_class": "com.vuelogix.location.model.LocationModel",
    "type": "Feature",
    "properties": {
        "address": "Purna to Loha Rd, Maharashtra 431511, India",
        "device_id": 23613,
        "last_updated": "2018-01-22T08:26:47.237Z"
    },
    "geometry": {
        "_class": "com.vuelogix.location.model.geojson.geometry.Point",
        "coordinates": [77.065659, 19.145168],
        "type": "Point"
    }
}

[23658] => {
    "_id": "5a65ae1e992e3c2572f74114",
    "_class": "com.vuelogix.location.model.LocationModel",
    "type": "Feature",
    "properties": {
        "address": "Taranagar - Churu Rd, Chalkoi Baneerotan, Rajasthan 331001, India",
        "device_id": 23658,
        "last_updated": "2018-01-22T09:25:50.893Z"
    },
    "geometry": {
        "_class": "com.vuelogix.location.model.geojson.geometry.Point",
        "coordinates": [74.956284, 28.497661],
        "type": "Point"
    }
}

Is there any way to get a result like this without iterating through records?


Solution

  • Use the $addFields pipeline stage to create a new field say root that is an array of a document that contains two fields, k and v where:

    The k field contains the field name.
    The v field contains the value of the field.
    

    In your case k should be the device_id field. Since this is a double type, you need a hack to convert it to a string for later. So your initial pipeline looks as follows:

    db.collection.aggregate([
        {
            "$addFields": {
                "root": [
                    {
                        "k": { "$substr": [ "$properties.device_id", 0, -1 ] },
                        "v": "$$ROOT"
                    }
                ]                
            }
        }
    ])
    

    which will return the following documents

    /* 1 */
    {
        "_id" : "5a65a047992e3c2572f74102",
        "_class" : "com.vuelogix.location.model.LocationModel",
        "type" : "Feature",
        "properties" : {
            "address" : "Purna to Loha Rd, Maharashtra 431511, India",
            "device_id" : 23613.0,
            "last_updated" : "2018-01-22T08:26:47.237Z"
        },
        "geometry" : {
            "_class" : "com.vuelogix.location.model.geojson.geometry.Point",
            "coordinates" : [ 
                77.065659, 
                19.145168
            ],
            "type" : "Point"
        },
        "root" : [ 
            {
                "k" : "23613",
                "v" : {
                    "_id" : "5a65a047992e3c2572f74102",
                    "_class" : "com.vuelogix.location.model.LocationModel",
                    "type" : "Feature",
                    "properties" : {
                        "address" : "Purna to Loha Rd, Maharashtra 431511, India",
                        "device_id" : 23613.0,
                        "last_updated" : "2018-01-22T08:26:47.237Z"
                    },
                    "geometry" : {
                        "_class" : "com.vuelogix.location.model.geojson.geometry.Point",
                        "coordinates" : [ 
                            77.065659, 
                            19.145168
                        ],
                        "type" : "Point"
                    }
                }
            }
        ]
    }
    
    /* 2 */
    {
        "_id" : "5a65ae1e992e3c2572f74114",
        "_class" : "com.vuelogix.location.model.LocationModel",
        "type" : "Feature",
        "properties" : {
            "address" : "Taranagar - Churu Rd, Chalkoi Baneerotan, Rajasthan 331001, India",
            "device_id" : 23658.0,
            "last_updated" : "2018-01-22T09:25:50.893Z"
        },
        "geometry" : {
            "_class" : "com.vuelogix.location.model.geojson.geometry.Point",
            "coordinates" : [ 
                74.956284, 
                28.497661
            ],
            "type" : "Point"
        },
        "root" : [ 
            {
                "k" : "23658",
                "v" : {
                    "_id" : "5a65ae1e992e3c2572f74114",
                    "_class" : "com.vuelogix.location.model.LocationModel",
                    "type" : "Feature",
                    "properties" : {
                        "address" : "Taranagar - Churu Rd, Chalkoi Baneerotan, Rajasthan 331001, India",
                        "device_id" : 23658.0,
                        "last_updated" : "2018-01-22T09:25:50.893Z"
                    },
                    "geometry" : {
                        "_class" : "com.vuelogix.location.model.geojson.geometry.Point",
                        "coordinates" : [ 
                            74.956284, 
                            28.497661
                        ],
                        "type" : "Point"
                    }
                }
            }
        ]
    }
    

    From here you would want to leverage the $arrayToObject operator so that you convert the newly added root to an object with device_id as the key:

    db.collection.aggregate([
        {
            "$addFields": {
                "root": [
                    {
                        "k": { "$substr": [ "$properties.device_id", 0, -1 ] },
                        "v": "$$ROOT"
                    }
                ]                
            }
        },
        {
            "$addFields": {
                "root": {
                    "$arrayToObject": "$root"
                }             
            }
        }
    ])
    

    which outputs:

    /* 1 */
    {
        "_id" : "5a65a047992e3c2572f74102",
        "_class" : "com.vuelogix.location.model.LocationModel",
        "type" : "Feature",
        "properties" : {
            "address" : "Purna to Loha Rd, Maharashtra 431511, India",
            "device_id" : 23613.0,
            "last_updated" : "2018-01-22T08:26:47.237Z"
        },
        "geometry" : {
            "_class" : "com.vuelogix.location.model.geojson.geometry.Point",
            "coordinates" : [ 
                77.065659, 
                19.145168
            ],
            "type" : "Point"
        },
        "root" : {
            "23613" : {
                "_id" : "5a65a047992e3c2572f74102",
                "_class" : "com.vuelogix.location.model.LocationModel",
                "type" : "Feature",
                "properties" : {
                    "address" : "Purna to Loha Rd, Maharashtra 431511, India",
                    "device_id" : 23613.0,
                    "last_updated" : "2018-01-22T08:26:47.237Z"
                },
                "geometry" : {
                    "_class" : "com.vuelogix.location.model.geojson.geometry.Point",
                    "coordinates" : [ 
                        77.065659, 
                        19.145168
                    ],
                    "type" : "Point"
                }
            }
        }
    }
    
    /* 2 */
    {
        "_id" : "5a65ae1e992e3c2572f74114",
        "_class" : "com.vuelogix.location.model.LocationModel",
        "type" : "Feature",
        "properties" : {
            "address" : "Taranagar - Churu Rd, Chalkoi Baneerotan, Rajasthan 331001, India",
            "device_id" : 23658.0,
            "last_updated" : "2018-01-22T09:25:50.893Z"
        },
        "geometry" : {
            "_class" : "com.vuelogix.location.model.geojson.geometry.Point",
            "coordinates" : [ 
                74.956284, 
                28.497661
            ],
            "type" : "Point"
        },
        "root" : {
            "23658" : {
                "_id" : "5a65ae1e992e3c2572f74114",
                "_class" : "com.vuelogix.location.model.LocationModel",
                "type" : "Feature",
                "properties" : {
                    "address" : "Taranagar - Churu Rd, Chalkoi Baneerotan, Rajasthan 331001, India",
                    "device_id" : 23658.0,
                    "last_updated" : "2018-01-22T09:25:50.893Z"
                },
                "geometry" : {
                    "_class" : "com.vuelogix.location.model.geojson.geometry.Point",
                    "coordinates" : [ 
                        74.956284, 
                        28.497661
                    ],
                    "type" : "Point"
                }
            }
        }
    }
    

    The last step in the pipeline would be to use $replaceRoot pipeline operator to get your desired output:

    db.collection.aggregate([
        {
            "$addFields": {
                "root": [
                    {
                        "k": { "$substr": [ "$properties.device_id", 0, -1 ] },
                        "v": "$$ROOT"
                    }
                ]                
            }
        },
        {
            "$addFields": {
                "root": {
                    "$arrayToObject": "$root"
                }             
            }
        },
        { "$replaceRoot" : { "newRoot": "$root" } }    
    ])
    

    Output

    /* 1 */
    {
        "23613" : {
            "_id" : "5a65a047992e3c2572f74102",
            "_class" : "com.vuelogix.location.model.LocationModel",
            "type" : "Feature",
            "properties" : {
                "address" : "Purna to Loha Rd, Maharashtra 431511, India",
                "device_id" : 23613.0,
                "last_updated" : "2018-01-22T08:26:47.237Z"
            },
            "geometry" : {
                "_class" : "com.vuelogix.location.model.geojson.geometry.Point",
                "coordinates" : [ 
                    77.065659, 
                    19.145168
                ],
                "type" : "Point"
            }
        }
    }
    
    /* 2 */
    {
        "23658" : {
            "_id" : "5a65ae1e992e3c2572f74114",
            "_class" : "com.vuelogix.location.model.LocationModel",
            "type" : "Feature",
            "properties" : {
                "address" : "Taranagar - Churu Rd, Chalkoi Baneerotan, Rajasthan 331001, India",
                "device_id" : 23658.0,
                "last_updated" : "2018-01-22T09:25:50.893Z"
            },
            "geometry" : {
                "_class" : "com.vuelogix.location.model.geojson.geometry.Point",
                "coordinates" : [ 
                    74.956284, 
                    28.497661
                ],
                "type" : "Point"
            }
        }
    }