Skip to content

Support expressions in query field projections. #3585

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from

Conversation

christophstrobl
Copy link
Member

@christophstrobl christophstrobl commented Mar 10, 2021

Starting with MongoDB 4.4 it is possible to use the aggregation expressions syntax for field projections as shown below.

query.fields()
  // Use a native expression. The used field names must refer to the ones of the document within the database.
  .project(MongoExpression.expressionFromString("'$toUpper' : '$last_name'"))
  // Assign the field name that shall hold the expression result in the target document.
  .as("last_name"); 

query.fields()
  // AggregationExpression makes sure field names are mapped to the ones used in the domain model.
  .project(StringOperators.valueOf("lastname").toUpper()) 
  .as("last_name");

query.fields()
  // Use SpEL along with an AggregationExpression to invoke expression functions.
  .project(AggregationSpELExpression.expressionOf("toUpper(lastname)"))
  .as("last_name");

@Query(fields='...') allows usage of expression field projections at Repository level.

Closes: #3583

* @param <T>
* @return never {@literal null}.
*/
default <T extends MongoExpression> T as(Function<MongoExpression, T> function) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about map?

Copy link
Member Author

@christophstrobl christophstrobl Mar 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intentionally did not name this one map, as I wanted to keep that method name available. I sounds like a better fit for getting called by the mapping layer to apply conversion.

* @see org.springframework.data.mongodb.core.aggregation.DateOperators
* @see org.springframework.data.mongodb.core.aggregation.ObjectOperators
* @see org.springframework.data.mongodb.core.aggregation.SetOperators
* @see org.springframework.data.mongodb.core.aggregation.StringOperators @
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: There's a lingering @

* @param json must not be {@literal null}.
* @return new instance of {@link MongoExpression}.
*/
static MongoExpression expressionFromString(String json) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about parse?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two things:

  • static import clashes with eg. org.bson.Document.parse
  • the expression must not be evaluated immediately which is something I'd expect from parse.

// explicit via dedicated AggregationExpression
query.fields()
  .project(StringOperators.valueOf("name").toUpper())
  .as("name");

// with a user provided expression parsed from a String
query.fields().project(MongoExpression.from("'$toUpper' : '$name'"))
  .as("name")

// using SpEL support
query.fields().project(AggregationSpELExpression.expressionOf("toUpper(name)"))
  .as("name");

// with parameter binding
query.fields().project(
    MongoExpression.from("'$toUpper' : '?0'").bind("$name")
  ).as("name")

// via the @query annotation on repositories
@query(value = "{ 'id' : ?0 }", fields = "{ 'name': { '$toUpper': '$name' } }")
- MongoExpresssion#expressionFromString(String) -> MongoExpresssion#create
- AggregationExpression#create(MongoExpression) ->A ggregationExpression#from
- MongoExpression#as -> removed from public API
mp911de pushed a commit that referenced this pull request Mar 18, 2021
// explicit via dedicated AggregationExpression
query.fields()
  .project(StringOperators.valueOf("name").toUpper())
  .as("name");

// with a user provided expression parsed from a String
query.fields().project(MongoExpression.create("'$toUpper' : '$name'"))
  .as("name")

// using SpEL support
query.fields().project(AggregationSpELExpression.expressionOf("toUpper(name)"))
  .as("name");

// with parameter binding
query.fields().project(
    MongoExpression.create("'$toUpper' : '?0'").bind("$name")
  ).as("name")

// via the @query annotation on repositories
@query(value = "{ 'id' : ?0 }", fields = "{ 'name': { '$toUpper': '$name' } }")

Closes: #3583
Original pull request: #3585.
mp911de added a commit that referenced this pull request Mar 18, 2021
Reorder methods. Tweak Javadoc and documentation wording. Mention projection expressions in the what's new section. Reformat code.

See #3583
Original pull request: #3585.
@mp911de mp911de added the type: enhancement A general enhancement label Mar 18, 2021
@mp911de mp911de added this to the 3.2 RC1 (2021.0.0) milestone Mar 18, 2021
@mp911de mp911de closed this Mar 18, 2021
@mp911de mp911de deleted the issue/3583 branch March 18, 2021 11:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support aggregation expression on fields projection.
2 participants