开发者

Can any of the noSql databases fetch data by particular field regardless of the filed location in the document?

For example if in the DB there are these documents:

> db.things.find()
[ 
  {"_id" : {"$oid" : "4e0748eecc93747e680421c7"},
          "title" : "aaaa"},
  {"_id" : {"$开发者_运维问答oid" : "4e074954cc93747e680421c8"},
          "desc" : "bbb",
          "children" : [
            {"title" : "ccc"},
            {"title" : "ddd"}
            ]
  }
  {"_id" : {"$oid" : "4e074a5abbdr4664546e59334"},
          "desc" : "none",
          "children" : [
            {"desc" : "ccc"}
            ]
  }
]

And I want to get all to documents that have “title” field in them and I don’t know where that field is located in the document. Does Mongodb/Couchdb or any other document db have this kind of querying option?


You would be able to accomplish this with a CouchDB Map-Reduce query. You'll need to write a function that recursively searches the document for that specified field. Since CouchDB only updates view indexes incrementally, the search will only occur each time a document is either created or updated.

If you want some actual source code to write such a map function, I'm sure I could whip something up. But it is possible with CouchDB. :)

EDIT: I spent a few minutes hacking a recursive scanning function. It isn't fully tested, but should be a very nice start for you if it doesn't work already.

I added a couple convenience functions for type testing, and the main function is called scan. It takes 2 parameters, an input and a function to call for each match.

It will loop through the input. If the input is an object, it will inspect the keys of that object, if an array, it will recursively call scan for each of the items in the array. Once the input is an object, it will check each key, if the name is title, it calls the passed function with the value as it's first parameter. Otherwise, it calls scan, in case the value is another object or array.

At the end of the map function, it passes in the document, as well as a function that simply calls emit with the value of the title.

function (doc) {
    function is_array(input) {
        return (input.constructor.toString().indexOf("Array") != -1);
    }

    function is_object(input) {
        return (typeof input === "object" && input !== null);
    }

    function scan(obj, func) {
        if (!obj || !is_object(obj)) {
            return false;
        }

        var x;

        if (is_object(obj)) {
            for (x in obj) {
                if (x.toLowerCase() === "title") {
                    func(obj[x]);
                } else {
                    scan(obj[x], func);
                }
            }
        } else if (is_array(obj)) {
            for (x = 0; x <= obj.length; x++) {
                scan(obj[x], func);
            }
        }
    }

    scan(doc, function (value) {
        emit(value);
    });
}


Such a search-everywhere functionality is not available in MongoDB - at least not out-of-the-box and not in a generic way. Map-Reduce with a related implementation dealing with nested documents are one option or application-side filtering is another one.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜