mongodbdictionarygoslicemgo

Get names of all keys in the collection using Go


I'd like to get the names of all the keys in a MongoDB collection.

For example, from this:

 "Id": ObjectId("5f5a010d431c4519dcda0e3d")
            "title": "App"
            "query": ""
            "db": ""
            "widgettype": ""
            "tablename": "active_instance"
            fields:Object
                user:"name",
                key:"passcode"
            "status": "active"
            "inlibrary": ""
            "createdts": 1599733804

Using "gopkg.in/mgo.v2" and "gopkg.in/mgo.v2/bson" packages.

err := mongodbSession.DB(dbName).C(collectionName).Find(bson.M{}).One(&result)
var keyset []string
    for index, _ := range result {
        fmt.Printf("%+v\n", index)
        keyset = append(keyset, index)
    }

    fmt.Println(keyset)

getting output as this

[_id title query db widgettype  status fields inlibrary createdts ]

child key is not being featched that is user and key.


Solution

  • Embedded documents will appear as another bson.M values inside your result, so you have to use a recursion to also traverse those.

    Here's how you can do that:

    func getKeys(m bson.M) (keys []string) {
        for k, v := range m {
            keys = append(keys, k)
            if m2, ok := v.(bson.M); ok {
                keys = append(keys, getKeys(m2)...)
            }
        }
        return
    }
    

    Example using it:

    m := bson.M{"Id": bson.ObjectId("5f5a010d431c4519dcda0e3d"),
        "title":      "App",
        "query":      "",
        "db":         "",
        "widgettype": "",
        "tablename":  "active_instance",
        "fields": bson.M{
            "user": "name",
            "key":  "passcode",
        },
        "status":    "active",
        "inlibrary": "",
        "createdts": 1599733804,
    }
    
    keys := getKeys(m)
    fmt.Println(keys)
    

    Which will output (try it on the Go Playground):

    [db widgettype createdts inlibrary _id title query tablename
      fields user key status]
    

    If you look at the results, user and key are included, but it's not possible to tell if they were fields of the document or that of an embedded document.

    You may choose to prefix fields of embedded documents with the field name of the embedded document field itself, e.g. to get fields.user and fields.key.

    This is how you can do that:

    func getKeys(m bson.M) (keys []string) {
        for k, v := range m {
            keys = append(keys, k)
            if m2, ok := v.(bson.M); ok {
                for _, k2 := range getKeys(m2) {
                    keys = append(keys, k+"."+k2)
                }
            }
        }
        return
    }
    

    Which would output (try it on the Go Playground):

    [createdts title query db status inlibrary _id widgettype tablename
        fields fields.user fields.key]
    

    Also note that the above solutions do not handle arrays. If you have arrays, you should also iterate over them, and if they contain another array or object, you should do the same (recursively). It's an exercise for you to extend it to handle arrays too.