问题
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