Project different embedded structures to same name

2019-05-07 00:21发布

问题:

I am writing a python script that performs these tasks:

  • Query a MongoDB Collection with embeded documents
  • Aggregate and Project to change the field names that are returned in the query to match a "u_" convention
  • Import the values to ServiceNow via REST API

ISSUE:

The embedded documents are not in a consistent structure. The HOSTNAME field is stored in varying structures.

I need to return the hostname as u_hostname. I need the value of $hostnames.name if it exists OR the value of $hostname if it exists.

How can I determine if either one exists, and return it as u_hostname?

Structure 1 Hostname stored as $hostnames.name

{
    "_id" : "192.168.1.1",
    "addresses" : {
        "ipv4" : "192.168.1.1"
    },
    "hostnames" : [ 
        {
            "type" : "PTR",
            "name" : "example.hostname.com"
        }
    ]
}

Structure 2 Hostname stored as $hostname

{
    "_id" : "192.168.2.1",
    "addresses" : {
        "ipv4" : "192.168.2.1"
    },
    "hostname" : "helloworld.com",

}

Script:

The query will only return the value of $hostname, not $hostname.name.

cmp = db['computers'].aggregate([
        {"$project" : {
                "_id":0,
                "u_hostname": "$hostnames.name",
                "u_hostname": "$hostname",
                "u_ipv4": "$addresses.ipv4"
        }}
])

回答1:

You can use the $ifNull operator to $project the "hostname" field.

cmp = db['computers'].aggregate([
    {"$project": { 
        "u_hostname": {
            "$ifNull": [
                "$hostnames.name", 
                { "$map": { 
                    "input": {"$literal": ["A"]}, 
                    "as": "el", 
                    "in": "$hostname"
                }}
            ]
        }, 
        "_id": 0, 
        "u_ipv4": "$addresses.ipv4"
    }},
    {"$unwind": "$u_hostname"}
])


回答2:

You want the $unwind, $group and $setUnion operators included in the aggregate function. It will allow you to flatten you list of hostnames.name and then union them with the other hostnames.