mongodb $where query to fetch sub-document content

只愿长相守 提交于 2019-12-23 04:43:10

问题


Below mongodb query is not returning the document. What is wrong with the query? I want to specify $where to match an element in array

[EDIT] Above problem is a simplified version of my scenario. I am using a spring data mongodb repository. I want to specify the query using @Query annotation. Was hoping the $where part to be simple comparison and not a full fledged javascript function. something like

@Query ( value=" { flag: true, $where: \"this.versions.version == this.defaultVersion \"}", fields = "{'versions' : 1}" )
Foo getDefaultVersion();

If $where is not the correct syntax, please suggest alternatives.

db.foo.find({
    flag: true,
    $where: "this.versions.version == this.defaultVersion " },
    { 'versions' : 1}
});

Collection:

{
    flag: true,
    defaultVersion: "1.0",
    versions: [
        {
            version: "1.0",
            tags: ["abc", "def"]
        },
        {
            version: "1.1",
            tags: ["abc", "def"]
        }
    ]
}

I want to fetch the "version" sub-document from versions array which has matching version as defaultVersion property.

[EDIT2] I was able to narrow it down using $elemMatch

db.foo.find({
    flag: true,
    versions: { $elemMatch : { version: '1.0' } } 
    },
    { 'versions' : 1}
});

In the above in place of hardcoded '1.0', I would like to specify the defaultVersion of the document. Not sure how do I achieve it?


回答1:


Using the $where operator should be avoided in most cases as it is both going to invoke a full collection scan regardless of what other conditions could possibly use an index selection.

In addition you are invoking the JavaScript interpreter over each result document, which is going to be considerably slower than native code. Read the warnings on the manual page, they are there for a reason

Where possible, please try to use .aggregate() for this type of comparison instead. In your case it is definitely the better option:

db.foo.aggregate([
    { "$match": { "flag": true } },
    { "$unwind": "$versions" },
    { "$project": {
        "versions": "$versions"
        "same": { "$eq": [ "$versions.version", "$defaultVersion" ] }
    }}
    { "$match": { "same": true } },
    { "$project": {
        "_id": 0,
        "versions": 1
    }}
])

This allows you to first filter your query by the "flag" condition and then inspect each member of the array to compare if the two fields are the same.

If necessary you can then roll back the matched array elements into an array where there is more than one match. But I don't think that is your requirement.




回答2:


Try this:

db.so.find({
    flag: true,
    $where: function () {
        var versions = this.versions; 
        for (var i=0; i<versions.length; i++) {
            if (versions[i].version == this.defaultVersion) return true;
        }
    }
});

[EDIT] Jack edited his question saying he doesn't want to use a JavaScript function but rather a simple expression. I don't think this is possible.



来源:https://stackoverflow.com/questions/22844348/mongodb-where-query-to-fetch-sub-document-content

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!