Spring mongo query collection on property with und

2019-07-16 10:46发布

问题:

I'm building a query to retrieve elements from a mongo collection, using MongoTemplate. The query criteria contains a property with an underscore, that somehow is replaced with '._', making the query always return 0 elements.

Criteria matchingCriteria = Criteria
.where("entries").elemMatch(Criteria.where("app_id").is(appId))

Looking to the logs I can see the generated query as follows:

o.s.data.mongodb.core.MongoTemplate: find using query: { "entries" : { "$elemMatch" : { "app._id" : "5834718ab0"}}} fields: null for class: Ranking in collection: ranking

I've already tried with BasicQuery, slashing underscore with '\\', and using the unicode “app\u005Fid". None of them worked. It's important to note that a collection with name "app" exists in my database.

The behaviour doesn't look standard. When I use another property with an underscore the value is not replaced:

Criteria matchingCriteria = Criteria .where("entries").elemMatch(Criteria.where("unique_app_id").‌​is(appId)) 

The logs:

o.s.data.mongodb.core.MongoTemplate find using query: { "entries" : { "$elemMatch" : { "unique_app_id" : "1131706359"}}} fields: null for class: class Ranking in collection: ranking

entries is an array with collection with the following format:

{
    "instanceId" : "654ba2d16579e",
    "app_id" : "583471adb0",
    "unique_app_id" : "554577506",
    "value" : 169
 }

It's worth mentioning that the same query (without the underscore replacement) works fine in a mongo IDE (Robomongo in this case).

I'm using spring-boot-starter-data-mongodb 1.4.1.RELEASE.

I'm really out of ideas right now.

Any suggestion ?

回答1:

Per section 3.4.3 of this Spring Data Commons documentation:

As we treat underscore as a reserved character we stongly advise to follow standard Java naming conventions (i.e. not using underscores in property names but camel case instead).

I don't believe you can use an underscore character in the middle of an element's name using Spring. Manual references are named after the referenced collection. Use the document type (collection name in singular) followed by _id ( <document>_id ). This is the only case where you can use underscore in the middle.

Update: Here is an existing pull request for the exact behavior you're seeing, as well as Spring's bug tracker for it.

From the Mongo shell, I can execute the following query with success:

> db.app.findOne({ "entries" : { "$elemMatch" : { "app_id" : "1"}}})
{
    "_id" : ObjectId("58a5bc6afa8dd4ae3097d5f7"),
    "name" : "Keith",
    "entries" : [
        {
            "instanceId" : "654ba2d16579e",
            "app_id" : "1"
        }
    ]
}

So, perhaps the Spring API doesn't split when it finds multiple _ tokens when parsing a criteria, but does split for traversal when parsing one.