From d7bf127a23f9e81d8a168ceb2baffd1c4966cb7b Mon Sep 17 00:00:00 2001 From: Alexey Plotnik Date: Sun, 27 Mar 2016 23:10:49 +1000 Subject: [PATCH 1/6] DATAMONGO-1404 - Add support for $min and $max update operators. Original pull request: #353. CLA: 169820160330091912 (Alexey Plotnik) --- .../data/mongodb/core/query/Update.java | 28 ++++++ .../data/mongodb/core/query/UpdateTests.java | 97 +++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Update.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Update.java index 00e35280b8..9fce3ddbb6 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Update.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Update.java @@ -314,6 +314,34 @@ public Update multiply(String key, Number multiplier) { addMultiFieldOperation("$mul", key, multiplier.doubleValue()); return this; } + + /** + * Update using the {@literal $max} update modifier + * + * @see http://docs.mongodb.org/manual/reference/operator/update/max/ + * @param key + * @param value + * @return + */ + public Update max(String key, Object value) { + Assert.notNull(value, "Value must not be 'null'."); + addMultiFieldOperation("$max", key, value); + return this; + } + + /** + * Update using the {@literal $max} update modifier + * + * @see http://docs.mongodb.org/manual/reference/operator/update/min/ + * @param key + * @param value + * @return + */ + public Update min(String key, Object value) { + Assert.notNull(value, "Value must not be 'null'."); + addMultiFieldOperation("$min", key, value); + return this; + } /** * The operator supports bitwise {@code and}, bitwise {@code or}, and bitwise {@code xor} operations. diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/UpdateTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/UpdateTests.java index 37d9370326..d1c4591109 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/UpdateTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/UpdateTests.java @@ -504,4 +504,101 @@ public void registersMultiplePullAllClauses() { assertThat(pullAll.get("field1"), is(notNullValue())); assertThat(pullAll.get("field2"), is(notNullValue())); } + + + /** + * @see DATAMONGO-1404 + */ + @Test(expected = IllegalArgumentException.class) + public void maxShouldThrowExceptionForNullMultiplier() { + new Update().max("key", null); + } + + /** + * @see DATAMONGO-1404 + */ + @Test(expected = IllegalArgumentException.class) + public void minShouldThrowExceptionForNullMultiplier() { + new Update().min("key", null); + } + + /** + * @see DATAMONGO-1404 + */ + @Test + public void getUpdateObjectShouldReturnCorrectRepresentationForMax() { + + Update update = new Update().max("key", 10); + + assertThat(update.getUpdateObject(), equalTo(new BasicDBObjectBuilder().add("$max", new BasicDBObject("key", 10)) + .get())); + } + + /** + * @see DATAMONGO-1404 + */ + @Test + public void getUpdateObjectShouldReturnCorrectRepresentationForMin() { + + Update update = new Update().min("key", 10); + + assertThat(update.getUpdateObject(), equalTo(new BasicDBObjectBuilder().add("$min", new BasicDBObject("key", 10)) + .get())); + } + + /** + * @see DATAMONGO-1404 + */ + @Test + public void shouldSuppressPreviousValueForMax() { + + Update update = new Update().max("key", 10); + + update.max("key", 99); + + assertThat(update.getUpdateObject(), equalTo(new BasicDBObjectBuilder().add("$max", new BasicDBObject("key", 99)) + .get())); + } + + /** + * @see DATAMONGO-1404 + */ + @Test + public void shouldSuppressPreviousValueForMin() { + + Update update = new Update().min("key", 10); + + update.max("key", 99); + + assertThat(update.getUpdateObject(), equalTo(new BasicDBObjectBuilder().add("$min9", new BasicDBObject("key", 99)) + .get())); + } + + /** + * @see DATAMONGO-1404 + */ + @Test + public void getUpdateObjectShouldReturnCorrectDateRepresentationForMax() { + + final java.util.Date date = new java.util.Date(); + + Update update = new Update().max("key", date); + + assertThat(update.getUpdateObject(), equalTo(new BasicDBObjectBuilder().add("$max", new BasicDBObject("key", date)) + .get())); + } + + /** + * @see DATAMONGO-1404 + */ + @Test + public void getUpdateObjectShouldReturnCorrectDateRepresentationForMin() { + + final java.util.Date date = new java.util.Date(); + + Update update = new Update().min("key", date); + + assertThat(update.getUpdateObject(), equalTo(new BasicDBObjectBuilder().add("$min", new BasicDBObject("key", date)) + .get())); + } } From 987669b430043b8ee2d34abe26446c25f32666ae Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 30 Mar 2016 13:45:06 +0200 Subject: [PATCH 2/6] DATAMONGO-1404 - Polishing. Add author and since tags. Update license headers. Reformat code. Replace FQCN with import and simple class name. Remove final keyword in test methods. Add tests for numeric values. Update documentation. Original pull request: #353. --- .../data/mongodb/core/query/Update.java | 118 ++++++----- .../data/mongodb/core/MongoTemplateTests.java | 200 +++++++++++++++++- .../core/convert/UpdateMapperUnitTests.java | 41 +++- .../data/mongodb/core/query/UpdateTests.java | 89 ++++---- src/main/asciidoc/new-features.adoc | 4 + src/main/asciidoc/reference/mongodb.adoc | 10 +- 6 files changed, 345 insertions(+), 117 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Update.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Update.java index 9fce3ddbb6..8438e201b9 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Update.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Update.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 the original author or authors. + * Copyright 2010-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Date; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -35,13 +36,14 @@ /** * Class to easily construct MongoDB update clauses. - * + * * @author Thomas Risberg * @author Mark Pollack * @author Oliver Gierke * @author Becca Gaspard * @author Christoph Strobl * @author Thomas Darimont + * @author Alexey Plotnik */ public class Update { @@ -55,7 +57,7 @@ public enum Position { /** * Static factory method to create an Update using the provided key - * + * * @param key * @return */ @@ -69,7 +71,7 @@ public static Update update(String key, Object value) { * {@literal $set}. This means fields not given in the {@link DBObject} will be nulled when executing the update. To * create an only-updating {@link Update} instance of a {@link DBObject}, call {@link #set(String, Object)} for each * value in it. - * + * * @param object the source {@link DBObject} to create the update from. * @param exclude the fields to exclude. * @return @@ -99,7 +101,7 @@ public static Update fromDBObject(DBObject object, String... exclude) { /** * Update using the {@literal $set} update modifier - * + * * @see http://docs.mongodb.org/manual/reference/operator/update/set/ * @param key * @param value @@ -112,7 +114,7 @@ public Update set(String key, Object value) { /** * Update using the {@literal $setOnInsert} update modifier - * + * * @see http://docs.mongodb.org/manual/reference/operator/update/setOnInsert/ * @param key * @param value @@ -125,7 +127,7 @@ public Update setOnInsert(String key, Object value) { /** * Update using the {@literal $unset} update modifier - * + * * @see http://docs.mongodb.org/manual/reference/operator/update/unset/ * @param key * @return @@ -137,7 +139,7 @@ public Update unset(String key) { /** * Update using the {@literal $inc} update modifier - * + * * @see http://docs.mongodb.org/manual/reference/operator/update/inc/ * @param key * @param inc @@ -150,7 +152,7 @@ public Update inc(String key, Number inc) { /** * Update using the {@literal $push} update modifier - * + * * @see http://docs.mongodb.org/manual/reference/operator/update/push/ * @param key * @param value @@ -165,7 +167,7 @@ public Update push(String key, Object value) { * Update using {@code $push} modifier.
* Allows creation of {@code $push} command for single or multiple (using {@code $each}) values as well as using * {@code $position}. - * + * * @see http://docs.mongodb.org/manual/reference/operator/update/push/ * @see http://docs.mongodb.org/manual/reference/operator/update/each/ * @param key @@ -183,7 +185,7 @@ public PushOperatorBuilder push(String key) { * Update using the {@code $pushAll} update modifier.
* Note: In mongodb 2.4 the usage of {@code $pushAll} has been deprecated in favor of {@code $push $each}. * {@link #push(String)}) returns a builder that can be used to populate the {@code $each} object. - * + * * @see http://docs.mongodb.org/manual/reference/operator/update/pushAll/ * @param key * @param values @@ -197,7 +199,7 @@ public Update pushAll(String key, Object[] values) { /** * Update using {@code $addToSet} modifier.
* Allows creation of {@code $push} command for single or multiple (using {@code $each}) values - * + * * @param key * @return * @since 1.5 @@ -208,7 +210,7 @@ public AddToSetBuilder addToSet(String key) { /** * Update using the {@literal $addToSet} update modifier - * + * * @see http://docs.mongodb.org/manual/reference/operator/update/addToSet/ * @param key * @param value @@ -221,7 +223,7 @@ public Update addToSet(String key, Object value) { /** * Update using the {@literal $pop} update modifier - * + * * @see http://docs.mongodb.org/manual/reference/operator/update/pop/ * @param key * @param pos @@ -234,7 +236,7 @@ public Update pop(String key, Position pos) { /** * Update using the {@literal $pull} update modifier - * + * * @see http://docs.mongodb.org/manual/reference/operator/update/pull/ * @param key * @param value @@ -247,7 +249,7 @@ public Update pull(String key, Object value) { /** * Update using the {@literal $pullAll} update modifier - * + * * @see http://docs.mongodb.org/manual/reference/operator/update/pullAll/ * @param key * @param values @@ -260,7 +262,7 @@ public Update pullAll(String key, Object[] values) { /** * Update using the {@literal $rename} update modifier - * + * * @see http://docs.mongodb.org/manual/reference/operator/update/rename/ * @param oldName * @param newName @@ -273,7 +275,7 @@ public Update rename(String oldName, String newName) { /** * Update given key to current date using {@literal $currentDate} modifier. - * + * * @see http://docs.mongodb.org/manual/reference/operator/update/currentDate/ * @param key * @return @@ -287,7 +289,7 @@ public Update currentDate(String key) { /** * Update given key to current date using {@literal $currentDate : { $type : "timestamp" }} modifier. - * + * * @see http://docs.mongodb.org/manual/reference/operator/update/currentDate/ * @param key * @return @@ -301,7 +303,7 @@ public Update currentTimestamp(String key) { /** * Multiply the value of given key by the given number. - * + * * @see http://docs.mongodb.org/manual/reference/operator/update/mul/ * @param key must not be {@literal null}. * @param multiplier must not be {@literal null}. @@ -314,38 +316,44 @@ public Update multiply(String key, Number multiplier) { addMultiFieldOperation("$mul", key, multiplier.doubleValue()); return this; } - + /** - * Update using the {@literal $max} update modifier + * Update given key to the {@code value} if the {@code value} is greater than the current value of the field. * * @see http://docs.mongodb.org/manual/reference/operator/update/max/ - * @param key - * @param value + * @see https://docs.mongodb.org/manual/reference/bson-types/#faq-dev-compare-order-for-bson-types + * @param key must not be {@literal null}. + * @param value must not be {@literal null}. * @return + * @since 1.10 */ public Update max(String key, Object value) { - Assert.notNull(value, "Value must not be 'null'."); + + Assert.notNull(value, "Value for max operation must not be 'null'."); addMultiFieldOperation("$max", key, value); return this; } /** - * Update using the {@literal $max} update modifier + * Update given key to the {@code value} if the {@code value} is less than the current value of the field. * * @see http://docs.mongodb.org/manual/reference/operator/update/min/ - * @param key - * @param value + * @see https://docs.mongodb.org/manual/reference/bson-types/#faq-dev-compare-order-for-bson-types + * @param key must not be {@literal null}. + * @param value must not be {@literal null}. * @return + * @since 1.10 */ public Update min(String key, Object value) { - Assert.notNull(value, "Value must not be 'null'."); + + Assert.notNull(value, "Value for min operation must not be 'null'."); addMultiFieldOperation("$min", key, value); return this; } /** * The operator supports bitwise {@code and}, bitwise {@code or}, and bitwise {@code xor} operations. - * + * * @param key * @return * @since 1.7 @@ -360,7 +368,7 @@ public DBObject getUpdateObject() { /** * This method is not called anymore rather override {@link #addMultiFieldOperation(String, String, Object)}. - * + * * @param operator * @param key * @param value @@ -399,7 +407,7 @@ protected void addMultiFieldOperation(String operator, String key, Object value) /** * Determine if a given {@code key} will be touched on execution. - * + * * @param key * @return */ @@ -409,7 +417,7 @@ public boolean modifies(String key) { /** * Inspects given {@code key} for '$'. - * + * * @param key * @return */ @@ -417,7 +425,7 @@ private static boolean isKeyword(String key) { return StringUtils.startsWithIgnoreCase(key, "$"); } - /* + /* * (non-Javadoc) * @see java.lang.Object#hashCode() */ @@ -426,7 +434,7 @@ public int hashCode() { return getUpdateObject().hashCode(); } - /* + /* * (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @@ -456,7 +464,7 @@ public String toString() { /** * Modifiers holds a distinct collection of {@link Modifier} - * + * * @author Christoph Strobl * @author Thomas Darimont */ @@ -506,7 +514,7 @@ public boolean equals(Object obj) { /** * Marker interface of nested commands. - * + * * @author Christoph Strobl */ public static interface Modifier { @@ -524,7 +532,7 @@ public static interface Modifier { /** * Implementation of {@link Modifier} representing {@code $each}. - * + * * @author Christoph Strobl * @author Thomas Darimont */ @@ -567,7 +575,7 @@ public Object getValue() { return this.values; } - /* + /* * (non-Javadoc) * @see java.lang.Object#hashCode() */ @@ -576,7 +584,7 @@ public int hashCode() { return nullSafeHashCode(values); } - /* + /* * (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @@ -597,7 +605,7 @@ public boolean equals(Object that) { /** * {@link Modifier} implementation used to propagate {@code $position}. - * + * * @author Christoph Strobl * @since 1.7 */ @@ -622,7 +630,7 @@ public Object getValue() { /** * Builder for creating {@code $push} modifiers - * + * * @author Christoph Strobl * @author Thomas Darimont */ @@ -638,7 +646,7 @@ public class PushOperatorBuilder { /** * Propagates {@code $each} to {@code $push} - * + * * @param values * @return */ @@ -650,7 +658,7 @@ public Update each(Object... values) { /** * Forces values to be added at the given {@literal position}. - * + * * @param position needs to be greater than or equal to zero. * @return * @since 1.7 @@ -668,7 +676,7 @@ public PushOperatorBuilder atPosition(int position) { /** * Forces values to be added at given {@literal position}. - * + * * @param position can be {@literal null} which will be appended at the last position. * @return * @since 1.7 @@ -686,7 +694,7 @@ public PushOperatorBuilder atPosition(Position position) { /** * Propagates {@link #value(Object)} to {@code $push} - * + * * @param values * @return */ @@ -694,7 +702,7 @@ public Update value(Object value) { return Update.this.push(key, value); } - /* + /* * (non-Javadoc) * @see java.lang.Object#hashCode() */ @@ -710,7 +718,7 @@ public int hashCode() { return result; } - /* + /* * (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @@ -741,7 +749,7 @@ private Update getOuterType() { /** * Builder for creating {@code $addToSet} modifier. - * + * * @author Christoph Strobl * @since 1.5 */ @@ -755,7 +763,7 @@ public AddToSetBuilder(String key) { /** * Propagates {@code $each} to {@code $addToSet} - * + * * @param values * @return */ @@ -765,7 +773,7 @@ public Update each(Object... values) { /** * Propagates {@link #value(Object)} to {@code $addToSet} - * + * * @param values * @return */ @@ -795,7 +803,7 @@ public String toString() { /** * Creates a new {@link BitwiseOperatorBuilder}. - * + * * @param reference must not be {@literal null} * @param key must not be {@literal null} */ @@ -810,7 +818,7 @@ protected BitwiseOperatorBuilder(Update reference, String key) { /** * Updates to the result of a bitwise and operation between the current value and the given one. - * + * * @param value * @return */ @@ -822,7 +830,7 @@ public Update and(long value) { /** * Updates to the result of a bitwise or operation between the current value and the given one. - * + * * @param value * @return */ @@ -834,7 +842,7 @@ public Update or(long value) { /** * Updates to the result of a bitwise xor operation between the current value and the given one. - * + * * @param value * @return */ diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java index 86ce2a08b6..43ba0fe8cf 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateTests.java @@ -24,14 +24,17 @@ import static org.springframework.data.mongodb.core.query.Query.*; import static org.springframework.data.mongodb.core.query.Update.*; +import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; +import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import org.bson.types.ObjectId; @@ -94,7 +97,7 @@ /** * Integration test for {@link MongoTemplate}. - * + * * @author Oliver Gierke * @author Thomas Risberg * @author Amol Nayak @@ -102,6 +105,7 @@ * @author Thomas Darimont * @author Komi Innocent * @author Christoph Strobl + * @author Mark Paluch */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:infrastructure.xml") @@ -3164,6 +3168,194 @@ public void updateShouldWorkForTypesContainingGeoJsonTypes() { assertThat(template.findOne(query(where("id").is(wgj.id)), WithGeoJson.class).point, is(equalTo(wgj.point))); } + /** + * @see DATAMONGO-1404 + */ + @Test + public void updatesDateValueCorrectlyWhenUsingMinOperator() { + + Calendar cal = Calendar.getInstance(Locale.US); + cal.set(2013, 10, 13, 0, 0, 0); + + TypeWithDate twd = new TypeWithDate(); + twd.date = new Date(); + template.save(twd); + template.updateFirst(query(where("id").is(twd.id)), new Update().min("date", cal.getTime()), TypeWithDate.class); + + TypeWithDate loaded = template.find(query(where("id").is(twd.id)), TypeWithDate.class).get(0); + assertThat(loaded.date, equalTo(cal.getTime())); + } + + /** + * @see DATAMONGO-1404 + */ + @Test + public void updatesNumericValueCorrectlyWhenUsingMinOperator() { + + TypeWithNumbers twn = new TypeWithNumbers(); + twn.byteVal = 100; + twn.doubleVal = 200D; + twn.floatVal = 300F; + twn.intVal = 400; + twn.longVal = 500L; + + // Note that $min operator uses String comparison for BigDecimal/BigInteger comparison according to BSON sort rules. + twn.bigIntegerVal = new BigInteger("600"); + twn.bigDeciamVal = new BigDecimal("700.0"); + + template.save(twn); + + byte byteVal = 90; + Update update = new Update()// + .min("byteVal", byteVal) // + .min("doubleVal", 190D) // + .min("floatVal", 290F) // + .min("intVal", 390) // + .min("longVal", 490) // + .min("bigIntegerVal", new BigInteger("590")) // + .min("bigDeciamVal", new BigDecimal("690")) // + ; + + template.updateFirst(query(where("id").is(twn.id)), update, TypeWithNumbers.class); + + TypeWithNumbers loaded = template.find(query(where("id").is(twn.id)), TypeWithNumbers.class).get(0); + assertThat(loaded.byteVal, equalTo(byteVal)); + assertThat(loaded.doubleVal, equalTo(190D)); + assertThat(loaded.floatVal, equalTo(290F)); + assertThat(loaded.intVal, equalTo(390)); + assertThat(loaded.longVal, equalTo(490L)); + assertThat(loaded.bigIntegerVal, equalTo(new BigInteger("590"))); + assertThat(loaded.bigDeciamVal, equalTo(new BigDecimal("690"))); + } + + /** + * @see DATAMONGO-1404 + */ + @Test + public void updatesDateValueCorrectlyWhenUsingMaxOperator() { + + Calendar cal = Calendar.getInstance(Locale.US); + cal.set(2013, 10, 13, 0, 0, 0); + + TypeWithDate twd = new TypeWithDate(); + twd.date = cal.getTime(); + template.save(twd); + + cal.set(2019, 10, 13, 0, 0, 0); + template.updateFirst(query(where("id").is(twd.id)), new Update().max("date", cal.getTime()), TypeWithDate.class); + + TypeWithDate loaded = template.find(query(where("id").is(twd.id)), TypeWithDate.class).get(0); + assertThat(loaded.date, equalTo(cal.getTime())); + } + + /** + * @see DATAMONGO-1404 + */ + @Test + public void updatesNumericValueCorrectlyWhenUsingMaxOperator() { + + TypeWithNumbers twn = new TypeWithNumbers(); + twn.byteVal = 100; + twn.doubleVal = 200D; + twn.floatVal = 300F; + twn.intVal = 400; + twn.longVal = 500L; + + // Note that $max operator uses String comparison for BigDecimal/BigInteger comparison according to BSON sort rules. + twn.bigIntegerVal = new BigInteger("600"); + twn.bigDeciamVal = new BigDecimal("700.0"); + + template.save(twn); + + byte byteVal = 101; + Update update = new Update()// + .max("byteVal", byteVal) // + .max("doubleVal", 290D) // + .max("floatVal", 390F) // + .max("intVal", 490) // + .max("longVal", 590) // + .max("bigIntegerVal", new BigInteger("690")) // + .max("bigDeciamVal", new BigDecimal("790")) // + ; + + template.updateFirst(query(where("id").is(twn.id)), update, TypeWithNumbers.class); + + TypeWithNumbers loaded = template.find(query(where("id").is(twn.id)), TypeWithNumbers.class).get(0); + assertThat(loaded.byteVal, equalTo(byteVal)); + assertThat(loaded.doubleVal, equalTo(290D)); + assertThat(loaded.floatVal, equalTo(390F)); + assertThat(loaded.intVal, equalTo(490)); + assertThat(loaded.longVal, equalTo(590L)); + assertThat(loaded.bigIntegerVal, equalTo(new BigInteger("690"))); + assertThat(loaded.bigDeciamVal, equalTo(new BigDecimal("790"))); + } + + /** + * @see DATAMONGO-1404 + */ + @Test + public void updatesBigNumberValueUsingStringComparisonWhenUsingMaxOperator() { + + TypeWithNumbers twn = new TypeWithNumbers(); + + // Note that $max operator uses String comparison for BigDecimal/BigInteger comparison according to BSON sort rules. + // Therefore "80" is considered greater than "700" + twn.bigIntegerVal = new BigInteger("600"); + twn.bigDeciamVal = new BigDecimal("700.0"); + + template.save(twn); + + Update update = new Update()// + .max("bigIntegerVal", new BigInteger("70")) // + .max("bigDeciamVal", new BigDecimal("80")) // + ; + + template.updateFirst(query(where("id").is(twn.id)), update, TypeWithNumbers.class); + + TypeWithNumbers loaded = template.find(query(where("id").is(twn.id)), TypeWithNumbers.class).get(0); + assertThat(loaded.bigIntegerVal, equalTo(new BigInteger("70"))); + assertThat(loaded.bigDeciamVal, equalTo(new BigDecimal("80"))); + } + + /** + * @see DATAMONGO-1404 + */ + @Test + public void updatesBigNumberValueUsingStringComparisonWhenUsingMinOperator() { + + TypeWithNumbers twn = new TypeWithNumbers(); + + // Note that $max operator uses String comparison for BigDecimal/BigInteger comparison according to BSON sort rules. + // Therefore "80" is considered greater than "700" + twn.bigIntegerVal = new BigInteger("80"); + twn.bigDeciamVal = new BigDecimal("90.0"); + + template.save(twn); + + Update update = new Update()// + .min("bigIntegerVal", new BigInteger("700")) // + .min("bigDeciamVal", new BigDecimal("800")) // + ; + + template.updateFirst(query(where("id").is(twn.id)), update, TypeWithNumbers.class); + + TypeWithNumbers loaded = template.find(query(where("id").is(twn.id)), TypeWithNumbers.class).get(0); + assertThat(loaded.bigIntegerVal, equalTo(new BigInteger("700"))); + assertThat(loaded.bigDeciamVal, equalTo(new BigDecimal("800"))); + } + + static class TypeWithNumbers { + + @Id String id; + Integer intVal; + Float floatVal; + Long longVal; + Double doubleVal; + BigDecimal bigDeciamVal; + BigInteger bigIntegerVal; + Byte byteVal; + } + static class DoucmentWithNamedIdField { @Id String someIdKey; @@ -3215,11 +3407,11 @@ static class DocumentWithDBRefCollection { @Id public String id; - @Field("db_ref_list")/** @see DATAMONGO-1058 */ - @org.springframework.data.mongodb.core.mapping.DBRef// + @Field("db_ref_list") /** @see DATAMONGO-1058 */ + @org.springframework.data.mongodb.core.mapping.DBRef // public List dbRefAnnotatedList; - @org.springframework.data.mongodb.core.mapping.DBRef// + @org.springframework.data.mongodb.core.mapping.DBRef // public Sample dbRefProperty; } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java index feca9d76b9..c27ac91b9d 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/convert/UpdateMapperUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2015 the original author or authors. + * Copyright 2013-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -63,10 +63,11 @@ /** * Unit tests for {@link UpdateMapper}. - * + * * @author Oliver Gierke * @author Christoph Strobl * @author Thomas Darimont + * @author Mark Paluch */ @RunWith(MockitoJUnitRunner.class) public class UpdateMapperUnitTests { @@ -687,10 +688,8 @@ public void mappingShouldRetainTypeInformationOfNestedListWhenUpdatingConcreteyP context.getPersistentEntity(DomainTypeWrappingConcreteyTypeHavingListOfInterfaceTypeAttributes.class)); assertThat(mappedUpdate, isBsonObject().notContaining("$set.concreteTypeWithListAttributeOfInterfaceType._class")); - assertThat( - mappedUpdate, - isBsonObject().containing("$set.concreteTypeWithListAttributeOfInterfaceType.models.[0]._class", - ModelImpl.class.getName())); + assertThat(mappedUpdate, isBsonObject() + .containing("$set.concreteTypeWithListAttributeOfInterfaceType.models.[0]._class", ModelImpl.class.getName())); } /** @@ -757,8 +756,8 @@ public void mappingShouldRetrainTypeInformationWhenValueTypeOfMapDoesNotMatchIts @Test public void mappingShouldNotContainTypeInformationWhenValueTypeOfMapMatchesDeclaration() { - Map map = Collections. singletonMap("jasnah", new NestedDocument( - "kholin")); + Map map = Collections. singletonMap("jasnah", + new NestedDocument("kholin")); Update update = new Update().set("concreteMap", map); DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(), @@ -887,6 +886,32 @@ public void mapsAtomicIntegerToPrimitiveIntegerCorrectly() { assertThat($set.get("primIntValue"), Is. is(10)); } + /** + * @see DATAMONGO-1404 + */ + @Test + public void mapsMinCorrectly() { + + Update update = new Update().min("minfield", 10); + DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(), + context.getPersistentEntity(SimpleValueHolder.class)); + + assertThat(mappedUpdate, isBsonObject().containing("$min", new BasicDBObject("minfield", 10))); + } + + /** + * @see DATAMONGO-1404 + */ + @Test + public void mapsMaxCorrectly() { + + Update update = new Update().max("maxfield", 999); + DBObject mappedUpdate = mapper.getMappedObject(update.getUpdateObject(), + context.getPersistentEntity(SimpleValueHolder.class)); + + assertThat(mappedUpdate, isBsonObject().containing("$max", new BasicDBObject("maxfield", 999))); + } + static class DomainTypeWrappingConcreteyTypeHavingListOfInterfaceTypeAttributes { ListModelWrapper concreteTypeWithListAttributeOfInterfaceType; } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/UpdateTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/UpdateTests.java index d1c4591109..47cc8fee91 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/UpdateTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/UpdateTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 the original author or authors. + * Copyright 2010-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ import static org.junit.Assert.*; import java.util.Collections; +import java.util.Date; import java.util.Map; import org.joda.time.DateTime; @@ -31,12 +32,13 @@ /** * Test cases for {@link Update}. - * + * * @author Oliver Gierke * @author Thomas Risberg * @author Becca Gaspard * @author Christoph Strobl * @author Thomas Darimont + * @author Alexey Plotnik */ public class UpdateTests { @@ -114,9 +116,8 @@ public void testMultiplePushAllShouldBePossibleWhenUsingDifferentFields() { Update u = new Update().pushAll("authors", new Object[] { m1, m2 }); u.pushAll("books", new Object[] { "Spring in Action" }); - assertThat( - u.getUpdateObject().toString(), - is("{ \"$pushAll\" : { \"authors\" : [ { \"name\" : \"Sven\"} , { \"name\" : \"Maria\"}] , \"books\" : [ \"Spring in Action\"]}}")); + assertThat(u.getUpdateObject().toString(), is( + "{ \"$pushAll\" : { \"authors\" : [ { \"name\" : \"Sven\"} , { \"name\" : \"Maria\"}] , \"books\" : [ \"Spring in Action\"]}}")); } @Test @@ -343,10 +344,11 @@ public void testToString() { .set("foo", "bar"); assertThat(actualUpdate.toString(), is(equalTo(expectedUpdate.toString()))); - assertThat(actualUpdate.toString(), is("{ \"$inc\" : { \"size\" : 1} ," // - + " \"$set\" : { \"nl\" : null , \"directory\" : \"/Users/Test/Desktop\" , \"foo\" : \"bar\"} , " // - + "\"$push\" : { \"authors\" : { \"name\" : \"Sven\"}} " // - + ", \"$pop\" : { \"authors\" : -1}}")); // + assertThat(actualUpdate.toString(), + is("{ \"$inc\" : { \"size\" : 1} ," // + + " \"$set\" : { \"nl\" : null , \"directory\" : \"/Users/Test/Desktop\" , \"foo\" : \"bar\"} , " // + + "\"$push\" : { \"authors\" : { \"name\" : \"Sven\"}} " // + + ", \"$pop\" : { \"authors\" : -1}}")); // } /** @@ -367,9 +369,8 @@ public void getUpdateObjectShouldReturnCurrentDateCorrectlyForSingleFieldWhenUsi public void getUpdateObjectShouldReturnCurrentDateCorrectlyForMultipleFieldsWhenUsingDate() { Update update = new Update().currentDate("foo").currentDate("bar"); - assertThat(update.getUpdateObject(), - equalTo(new BasicDBObjectBuilder().add("$currentDate", new BasicDBObject("foo", true).append("bar", true)) - .get())); + assertThat(update.getUpdateObject(), equalTo( + new BasicDBObjectBuilder().add("$currentDate", new BasicDBObject("foo", true).append("bar", true)).get())); } /** @@ -379,10 +380,8 @@ public void getUpdateObjectShouldReturnCurrentDateCorrectlyForMultipleFieldsWhen public void getUpdateObjectShouldReturnCurrentDateCorrectlyForSingleFieldWhenUsingTimestamp() { Update update = new Update().currentTimestamp("foo"); - assertThat( - update.getUpdateObject(), - equalTo(new BasicDBObjectBuilder().add("$currentDate", - new BasicDBObject("foo", new BasicDBObject("$type", "timestamp"))).get())); + assertThat(update.getUpdateObject(), equalTo(new BasicDBObjectBuilder() + .add("$currentDate", new BasicDBObject("foo", new BasicDBObject("$type", "timestamp"))).get())); } /** @@ -392,12 +391,11 @@ public void getUpdateObjectShouldReturnCurrentDateCorrectlyForSingleFieldWhenUsi public void getUpdateObjectShouldReturnCurrentDateCorrectlyForMultipleFieldsWhenUsingTimestamp() { Update update = new Update().currentTimestamp("foo").currentTimestamp("bar"); - assertThat( - update.getUpdateObject(), - equalTo(new BasicDBObjectBuilder().add( - "$currentDate", - new BasicDBObject("foo", new BasicDBObject("$type", "timestamp")).append("bar", new BasicDBObject("$type", - "timestamp"))).get())); + assertThat(update.getUpdateObject(), + equalTo(new BasicDBObjectBuilder() + .add("$currentDate", new BasicDBObject("foo", new BasicDBObject("$type", "timestamp")).append("bar", + new BasicDBObject("$type", "timestamp"))) + .get())); } /** @@ -407,10 +405,10 @@ public void getUpdateObjectShouldReturnCurrentDateCorrectlyForMultipleFieldsWhen public void getUpdateObjectShouldReturnCurrentDateCorrectlyWhenUsingMixedDateAndTimestamp() { Update update = new Update().currentDate("foo").currentTimestamp("bar"); - assertThat( - update.getUpdateObject(), - equalTo(new BasicDBObjectBuilder().add("$currentDate", - new BasicDBObject("foo", true).append("bar", new BasicDBObject("$type", "timestamp"))).get())); + assertThat(update.getUpdateObject(), + equalTo(new BasicDBObjectBuilder() + .add("$currentDate", new BasicDBObject("foo", true).append("bar", new BasicDBObject("$type", "timestamp"))) + .get())); } /** @@ -439,8 +437,8 @@ public void multiplyShouldAddMultiplierAsItsDoubleValue() { Update update = new Update().multiply("key", 10); - assertThat(update.getUpdateObject(), equalTo(new BasicDBObjectBuilder().add("$mul", new BasicDBObject("key", 10D)) - .get())); + assertThat(update.getUpdateObject(), + equalTo(new BasicDBObjectBuilder().add("$mul", new BasicDBObject("key", 10D)).get())); } /** @@ -505,7 +503,6 @@ public void registersMultiplePullAllClauses() { assertThat(pullAll.get("field2"), is(notNullValue())); } - /** * @see DATAMONGO-1404 */ @@ -530,8 +527,8 @@ public void getUpdateObjectShouldReturnCorrectRepresentationForMax() { Update update = new Update().max("key", 10); - assertThat(update.getUpdateObject(), equalTo(new BasicDBObjectBuilder().add("$max", new BasicDBObject("key", 10)) - .get())); + assertThat(update.getUpdateObject(), + equalTo(new BasicDBObjectBuilder().add("$max", new BasicDBObject("key", 10)).get())); } /** @@ -542,8 +539,8 @@ public void getUpdateObjectShouldReturnCorrectRepresentationForMin() { Update update = new Update().min("key", 10); - assertThat(update.getUpdateObject(), equalTo(new BasicDBObjectBuilder().add("$min", new BasicDBObject("key", 10)) - .get())); + assertThat(update.getUpdateObject(), + equalTo(new BasicDBObjectBuilder().add("$min", new BasicDBObject("key", 10)).get())); } /** @@ -553,11 +550,10 @@ public void getUpdateObjectShouldReturnCorrectRepresentationForMin() { public void shouldSuppressPreviousValueForMax() { Update update = new Update().max("key", 10); - update.max("key", 99); - assertThat(update.getUpdateObject(), equalTo(new BasicDBObjectBuilder().add("$max", new BasicDBObject("key", 99)) - .get())); + assertThat(update.getUpdateObject(), + equalTo(new BasicDBObjectBuilder().add("$max", new BasicDBObject("key", 99)).get())); } /** @@ -567,11 +563,10 @@ public void shouldSuppressPreviousValueForMax() { public void shouldSuppressPreviousValueForMin() { Update update = new Update().min("key", 10); + update.min("key", 99); - update.max("key", 99); - - assertThat(update.getUpdateObject(), equalTo(new BasicDBObjectBuilder().add("$min9", new BasicDBObject("key", 99)) - .get())); + assertThat(update.getUpdateObject(), + equalTo(new BasicDBObjectBuilder().add("$min", new BasicDBObject("key", 99)).get())); } /** @@ -580,12 +575,11 @@ public void shouldSuppressPreviousValueForMin() { @Test public void getUpdateObjectShouldReturnCorrectDateRepresentationForMax() { - final java.util.Date date = new java.util.Date(); - + Date date = new Date(); Update update = new Update().max("key", date); - assertThat(update.getUpdateObject(), equalTo(new BasicDBObjectBuilder().add("$max", new BasicDBObject("key", date)) - .get())); + assertThat(update.getUpdateObject(), + equalTo(new BasicDBObjectBuilder().add("$max", new BasicDBObject("key", date)).get())); } /** @@ -594,11 +588,10 @@ public void getUpdateObjectShouldReturnCorrectDateRepresentationForMax() { @Test public void getUpdateObjectShouldReturnCorrectDateRepresentationForMin() { - final java.util.Date date = new java.util.Date(); - + Date date = new Date(); Update update = new Update().min("key", date); - assertThat(update.getUpdateObject(), equalTo(new BasicDBObjectBuilder().add("$min", new BasicDBObject("key", date)) - .get())); + assertThat(update.getUpdateObject(), + equalTo(new BasicDBObjectBuilder().add("$min", new BasicDBObject("key", date)).get())); } } diff --git a/src/main/asciidoc/new-features.adoc b/src/main/asciidoc/new-features.adoc index 50df5db996..fe68c7bedf 100644 --- a/src/main/asciidoc/new-features.adoc +++ b/src/main/asciidoc/new-features.adoc @@ -1,6 +1,10 @@ [[new-features]] = New & Noteworthy +[[new-features.1-10-0]] +== What's new in Spring Data MongoDB 1.10 +* Support for `$min` and `$max` operators to `Update`. + [[new-features.1-9-0]] == What's new in Spring Data MongoDB 1.9 * The following annotations have been enabled to build own, composed annotations: `@Document`, `@Id`, `@Field`, `@Indexed`, `@CompoundIndex`, `@GeoSpatialIndexed`, `@TextIndexed`, `@Query`, `@Meta`. diff --git a/src/main/asciidoc/reference/mongodb.adoc b/src/main/asciidoc/reference/mongodb.adoc index 46b7a1ee17..71a2b5812b 100644 --- a/src/main/asciidoc/reference/mongodb.adoc +++ b/src/main/asciidoc/reference/mongodb.adoc @@ -862,15 +862,21 @@ The Update class can be used with a little 'syntax sugar' as its methods are mea Here is a listing of methods on the Update class -* `Update` *addToSet* `(String key, Object value) ` Update using the `$addToSet` update modifier +* `Update` *addToSet* `(String key, Object value)` Update using the `$addToSet` update modifier +* `Update` *currentDate* `(String key)` Update using the `$currentDate` update modifier +* `Update` *currentTimestamp* `(String key)` Update using the `$currentDate` update modifier with `$type` `timestamp` * `Update` *inc* `(String key, Number inc)` Update using the `$inc` update modifier +* `Update` *max* `(String key, Object max)` Update using the `$max` update modifier +* `Update` *min* `(String key, Object min)` Update using the `$min` update modifier +* `Update` *multiply* `(String key, Number multiplier)` Update using the `$mul` update modifier * `Update` *pop* `(String key, Update.Position pos)` Update using the `$pop` update modifier * `Update` *pull* `(String key, Object value)` Update using the `$pull` update modifier * `Update` *pullAll* `(String key, Object[] values)` Update using the `$pullAll` update modifier -* `Update` *push* `(String key, Object value) ` Update using the `$push` update modifier +* `Update` *push* `(String key, Object value)` Update using the `$push` update modifier * `Update` *pushAll* `(String key, Object[] values)` Update using the `$pushAll` update modifier * `Update` *rename* `(String oldName, String newName)` Update using the `$rename` update modifier * `Update` *set* `(String key, Object value)` Update using the `$set` update modifier +* `Update` *setOnInsert* `(String key, Object value)` Update using the `$setOnInsert` update modifier * `Update` *unset* `(String key)` Update using the `$unset` update modifier [[mongo-template.upserts]] From ba575f1ca935fbb31a43073c52d4a7c6972af6ee Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 8 Apr 2016 16:12:09 +0200 Subject: [PATCH 3/6] DATAMONGO-1412 - Document mapping rules for Java types to MongoDB representation. Related pull request: #353 Related ticket: DATAMONGO-1412 --- src/main/asciidoc/reference/mapping.adoc | 180 +++++++++++++++++++++++ 1 file changed, 180 insertions(+) diff --git a/src/main/asciidoc/reference/mapping.adoc b/src/main/asciidoc/reference/mapping.adoc index b7873035d4..609a826c43 100644 --- a/src/main/asciidoc/reference/mapping.adoc +++ b/src/main/asciidoc/reference/mapping.adoc @@ -59,6 +59,186 @@ The following outlines what type conversion, if any, will be done on the propert When querying and updating `MongoTemplate` will use the converter to handle conversions of the `Query` and `Update` objects that correspond to the above rules for saving documents so field names and types used in your queries will be able to match what is in your domain classes. +[[mapping-conversion]] +== Data mapping and type conversion + +This section explain how types are mapped to a MongoDB representation and vice versa. Spring Data MongoDB supports all types that can be represented as BSON, MongoDB's internal document format. +In addition to these types, Spring Data MongoDB provides a set of built-in converters to map additional types. You can provide your own converters to adjust type conversion, see <> for further details. + +[cols="3,1,6", options="header"] +.Type +|=== +| Type +| Type conversion +| MongoDB representation + +| `String` +| native +| `{"firstname" : "Dave"}` + +| `double`, `Double`, `float`, `Float` +| native +| `{"weight" : 42.5}` + +| `int`, `Integer`, `short`, `Short` +| native + +32-bit integer +| `{"height" : 42}` + +| `long`, `Long` +| native + +64-bit integer +| `{"height" : 42}` + +| `Date`, `Timestamp` +| native +| `{"date" : ISODate("2019-11-12T23:00:00.809Z")}` + +| `byte[]` +| native +| `{"bin" : { "$binary" : "AQIDBA==", "$type" : "00" }}` + +| `Date` +| native +| `{"date" : ISODate("2019-11-12T23:00:00.809Z")}` + +| `ObjectId` +| native +| `{"_id" : ObjectId("5707a2690364aba3136ab870")}` + +| Array, `List`, `BasicDBList` +| native +| `{"cookies" : [ … ]}` + +| `boolean`, `Boolean` +| native +| `{"active" : true}` + +| `null` +| native +| `{"value" : null}` + +| `DBObject` +| native +| `{"value" : { … }}` + +| `AtomicInteger` + +calling `get()` before the actual conversion +| converter + +32-bit integer +| `{"value" : "741" }` + +| `AtomicLong` + +calling `get()` before the actual conversion +| converter + +64-bit integer +| `{"value" : "741" }` + +| `BigInteger` +| converter + +`String` +| `{"value" : "741" }` + +| `BigDecimal` +| converter + +`String` +| `{"value" : "741.99" }` + +| `URL` +| converter +| `{"website" : "http://projects.spring.io/spring-data-mongodb/" }` + +| `Locale` +| converter +| `{"locale : "en_US" }` + +| `char`, `Character` +| converter +| `{"char" : "a" }` + +| `NamedMongoScript` +| converter + +`Code` +| `{"_id" : "script name", value: (some javascript code)`} + +| `java.util.Currency` +| converter +| `{"currencyCode" : "EUR"}` + +| `LocalDate` + +(Joda, Java 8, JSR310-BackPort) +| converter +| `{"date" : ISODate("2019-11-12T00:00:00.000Z")}` + +| `LocalDateTime`, `LocalTime`, `Instant` + +(Joda, Java 8, JSR310-BackPort) +| converter +| `{"date" : ISODate("2019-11-12T23:00:00.809Z")}` + +| `DateTime` (Joda) +| converter +| `{"date" : ISODate("2019-11-12T23:00:00.809Z")}` + +| `DateMidnight` (Joda) +| converter +| `{"date" : ISODate("2019-11-12T00:00:00.000Z")}` + +| `ZoneId` (Java 8, JSR310-BackPort) +| converter +| `{"zoneId" : "ECT - Europe/Paris"}` + +| `Box` +| converter +| `{"box" : { "first" : { "x" : 1.0 , "y" : 2.0} , "second" : { "x" : 3.0 , "y" : 4.0}}` + +| `Polygon` +| converter +| `{"polygon" : { "points" : [ { "x" : 1.0 , "y" : 2.0} , { "x" : 3.0 , "y" : 4.0} , { "x" : 4.0 , "y" : 5.0}]}}` + +| `Circle` +| converter +| `{"circle" : { "center" : { "x" : 1.0 , "y" : 2.0} , "radius" : 3.0 , "metric" : "NEUTRAL"}}` + +| `Point` +| converter +| `{ "x" : 1.0 , "y" : 2.0}` + +| `GeoJsonPoint` +| converter +| `{"point" : { "type" : "Point" , "coordinates" : [3.0 , 4.0] }}` + +| `GeoJsonMultiPoint` +| converter +| `{"geoJsonLineString":{"type":"MultiPoint", "coordinates": [ [0,0],[0,1],[1,1] ] }}` + +| `Sphere` +| converter +| `{"sphere" : { "center" : { "x" : 1.0 , "y" : 2.0} , "radius" : 3.0 , "metric" : "NEUTRAL"}}` + +| `GeoJsonPolygon` +| converter +| `{"polygon" : { "type" : "Polygon", "coordinates" : [[ [ 0 , 0 ] , [ 3 , 6 ] , [ 6 , 1 ] , [ 0 , 0 ] ]] }}` + +| `GeoJsonMultiPolygon` +| converter +| `{"geoJsonMultiPolygon" : { "type" : "MultiPolygon", "coordinates" : [ + [ [ [ -73.958, 40.8003 ], [ -73.9498, 40.7968 ], ] ], + [ [ [ -73.9737, 40.7648 ], [ -73.958, 40.8003 ] ] ] + ] }}` + +| `GeoJsonLineString` +| converter +| `{ "geoJsonLineString" : {"type" : "LineString", "coordinates" : [ [ 40, 5 ], [ 41, 6 ] ]}}` + +| `GeoJsonMultiLineString` +| converter +| `{"geoJsonLineString" : {"type": "MultiLineString", coordinates: [ + [ [ -73.97162, 40.78205 ], [ -73.96374, 40.77715 ] ], + [ [ -73.97880, 40.77247 ], [ -73.97036, 40.76811 ] ] + ] }}` +|=== + + [[mapping-configuration]] == Mapping Configuration From 3de02cf3afa48cadaf976f3ad29f219e7cf66202 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 8 Apr 2016 16:32:04 +0200 Subject: [PATCH 4/6] DATAMONGO-1412 - Fix backticks and code element highlighting. Fixed broken highlighting using backticks followed by chars/single quotes. Convert single quote emphasis of id to backtick code fences. Add missing spaces between words and backticks. --- src/main/asciidoc/reference/mapping.adoc | 36 +++++++++---------- .../reference/mongo-repositories.adoc | 12 +++---- src/main/asciidoc/reference/mongodb.adoc | 36 +++++++++---------- 3 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/main/asciidoc/reference/mapping.adoc b/src/main/asciidoc/reference/mapping.adoc index 609a826c43..ac0d4dd627 100644 --- a/src/main/asciidoc/reference/mapping.adoc +++ b/src/main/asciidoc/reference/mapping.adoc @@ -12,25 +12,25 @@ NOTE: `SimpleMongoConverter` has been deprecated in Spring Data MongoDB M3 as al `MongoMappingConverter` has a few conventions for mapping objects to documents when no additional mapping metadata is provided. The conventions are: -* The short Java class name is mapped to the collection name in the following manner. The class '`com.bigbank.SavingsAccount`' maps to '`savingsAccount`' collection name. +* The short Java class name is mapped to the collection name in the following manner. The class `com.bigbank.SavingsAccount` maps to `savingsAccount` collection name. * All nested objects are stored as nested objects in the document and *not* as DBRefs * The converter will use any Spring Converters registered with it to override the default mapping of object properties to document field/values. * The fields of an object are used to convert to and from fields in the document. Public JavaBean properties are not used. * You can have a single non-zero argument constructor whose constructor argument names match top level field names of document, that constructor will be used. Otherwise the zero arg constructor will be used. if there is more than one non-zero argument constructor an exception will be thrown. [[mapping.conventions.id-field]] -=== How the '_id' field is handled in the mapping layer +=== How the `_id` field is handled in the mapping layer -MongoDB requires that you have an '_id' field for all documents. If you don't provide one the driver will assign a ObjectId with a generated value. The "_id" field can be of any type the, other than arrays, so long as it is unique. The driver naturally supports all primitive types and Dates. When using the `MongoMappingConverter` there are certain rules that govern how properties from the Java class is mapped to this '_id' field. +MongoDB requires that you have an `_id` field for all documents. If you don't provide one the driver will assign a ObjectId with a generated value. The "_id" field can be of any type the, other than arrays, so long as it is unique. The driver naturally supports all primitive types and Dates. When using the `MongoMappingConverter` there are certain rules that govern how properties from the Java class is mapped to this `_id` field. -The following outlines what field will be mapped to the '_id' document field: +The following outlines what field will be mapped to the `_id` document field: -* A field annotated with `@Id` (`org.springframework.data.annotation.Id`) will be mapped to the '_id' field. -* A field without an annotation but named 'id' will be mapped to the '_id' field. -* The default field name for identifiers is '_id' and can be customized via the `@Field` annotation. +* A field annotated with `@Id` (`org.springframework.data.annotation.Id`) will be mapped to the `_id` field. +* A field without an annotation but named `id` will be mapped to the `_id` field. +* The default field name for identifiers is `_id` and can be customized via the `@Field` annotation. [cols="1,2", options="header"] -.Examples for the translation of '_id'-field definitions +.Examples for the translation of `_id` field definitions |=== | Field definition | Resulting Id-Fieldname in MongoDB @@ -41,21 +41,21 @@ The following outlines what field will be mapped to the '_id' document field: | `@Field` `String` id | `_id` -| `@Field('x')` `String` id +| `@Field("x")` `String` id | `x` | `@Id` `String` x | `_id` -| `@Field('x')` `@Id` `String` x +| `@Field("x")` `@Id` `String` x | `_id` |=== The following outlines what type conversion, if any, will be done on the property mapped to the _id document field. -* If a field named 'id' is declared as a String or BigInteger in the Java class it will be converted to and stored as an ObjectId if possible. ObjectId as a field type is also valid. If you specify a value for 'id' in your application, the conversion to an ObjectId is detected to the MongoDBdriver. If the specified 'id' value cannot be converted to an ObjectId, then the value will be stored as is in the document's _id field. -* If a field named ' id' id field is not declared as a String, BigInteger, or ObjectID in the Java class then you should assign it a value in your application so it can be stored 'as-is' in the document's _id field. -* If no field named 'id' is present in the Java class then an implicit '_id' file will be generated by the driver but not mapped to a property or field of the Java class. +* If a field named `id` is declared as a String or BigInteger in the Java class it will be converted to and stored as an ObjectId if possible. ObjectId as a field type is also valid. If you specify a value for `id` in your application, the conversion to an ObjectId is detected to the MongoDBdriver. If the specified `id` value cannot be converted to an ObjectId, then the value will be stored as is in the document's _id field. +* If a field named `id` id field is not declared as a String, BigInteger, or ObjectID in the Java class then you should assign it a value in your application so it can be stored 'as-is' in the document's _id field. +* If no field named `id` is present in the Java class then an implicit `_id` file will be generated by the driver but not mapped to a property or field of the Java class. When querying and updating `MongoTemplate` will use the converter to handle conversions of the `Query` and `Update` objects that correspond to the above rules for saving documents so field names and types used in your queries will be able to match what is in your domain classes. @@ -288,11 +288,11 @@ public class GeoSpatialAppConfig extends AbstractMongoConfiguration { ---- ==== -`AbstractMongoConfiguration` requires you to implement methods that define a `com.mongodb.Mongo` as well as provide a database name. `AbstractMongoConfiguration` also has a method you can override named '`getMappingBasePackage`' which tells the converter where to scan for classes annotated with the `@org.springframework.data.mongodb.core.mapping.Document` annotation. +`AbstractMongoConfiguration` requires you to implement methods that define a `com.mongodb.Mongo` as well as provide a database name. `AbstractMongoConfiguration` also has a method you can override named `getMappingBasePackage(…)` which tells the converter where to scan for classes annotated with the `@Document` annotation. -You can add additional converters to the converter by overriding the method afterMappingMongoConverterCreation. Also shown in the above example is a `LoggingEventListener` which logs `MongoMappingEvent`s that are posted onto Spring's `ApplicationContextEvent` infrastructure. +You can add additional converters to the converter by overriding the method afterMappingMongoConverterCreation. Also shown in the above example is a `LoggingEventListener` which logs `MongoMappingEvent` s that are posted onto Spring's `ApplicationContextEvent` infrastructure. -NOTE: AbstractMongoConfiguration will create a MongoTemplate instance and registered with the container under the name 'mongoTemplate'. +NOTE: AbstractMongoConfiguration will create a MongoTemplate instance and registered with the container under the name `mongoTemplate`. You can also override the method `UserCredentials getUserCredentials()` to provide the username and password information to connect to the database. @@ -345,7 +345,7 @@ The `base-package` property tells it where to scan for classes annotated with th [[mapping-usage]] == Metadata based Mapping -To take full advantage of the object mapping functionality inside the Spring Data/MongoDB support, you should annotate your mapped objects with the `@org.springframework.data.mongodb.core.mapping.Document` annotation. Although it is not necessary for the mapping framework to have this annotation (your POJOs will be mapped correctly, even without any annotations), it allows the classpath scanner to find and pre-process your domain objects to extract the necessary metadata. If you don't use this annotation, your application will take a slight performance hit the first time you store a domain object because the mapping framework needs to build up its internal metadata model so it knows about the properties of your domain object and how to persist them. +To take full advantage of the object mapping functionality inside the Spring Data/MongoDB support, you should annotate your mapped objects with the `@Document` annotation. Although it is not necessary for the mapping framework to have this annotation (your POJOs will be mapped correctly, even without any annotations), it allows the classpath scanner to find and pre-process your domain objects to extract the necessary metadata. If you don't use this annotation, your application will take a slight performance hit the first time you store a domain object because the mapping framework needs to build up its internal metadata model so it knows about the properties of your domain object and how to persist them. .Example domain object ==== @@ -595,7 +595,7 @@ Simply declaring these beans in your Spring ApplicationContext will cause them t [[mapping-explicit-converters]] === Overriding Mapping with explicit Converters -When storing and querying your objects it is convenient to have a `MongoConverter` instance handle the mapping of all Java types to DBObjects. However, sometimes you may want the `MongoConverter`'s do most of the work but allow you to selectively handle the conversion for a particular type or to optimize performance. +When storing and querying your objects it is convenient to have a `MongoConverter` instance handle the mapping of all Java types to DBObjects. However, sometimes you may want the `MongoConverter` s do most of the work but allow you to selectively handle the conversion for a particular type or to optimize performance. To selectively handle the conversion yourself, register one or more one or more `org.springframework.core.convert.converter.Converter` instances with the MongoConverter. diff --git a/src/main/asciidoc/reference/mongo-repositories.adoc b/src/main/asciidoc/reference/mongo-repositories.adoc index d78880fcff..46dd88b06a 100644 --- a/src/main/asciidoc/reference/mongo-repositories.adoc +++ b/src/main/asciidoc/reference/mongo-repositories.adoc @@ -28,7 +28,7 @@ public class Person { ---- ==== -We have a quite simple domain object here. Note that it has a property named `id` of type`ObjectId`. The default serialization mechanism used in `MongoTemplate` (which is backing the repository support) regards properties named id as document id. Currently we support`String`, `ObjectId` and `BigInteger` as id-types. +We have a quite simple domain object here. Note that it has a property named `id` of type `ObjectId`. The default serialization mechanism used in `MongoTemplate` (which is backing the repository support) regards properties named id as document id. Currently we support `String`, `ObjectId` and `BigInteger` as id-types. .Basic repository interface to persist Person entities ==== @@ -99,7 +99,7 @@ class ApplicationConfig extends AbstractMongoConfiguration { ---- ==== -As our domain repository extends `PagingAndSortingRepository` it provides you with CRUD operations as well as methods for paginated and sorted access to the entities. Working with the repository instance is just a matter of dependency injecting it into a client. So accessing the second page of `Person`s at a page size of 10 would simply look something like this: +As our domain repository extends `PagingAndSortingRepository` it provides you with CRUD operations as well as methods for paginated and sorted access to the entities. Working with the repository instance is just a matter of dependency injecting it into a client. So accessing the second page of `Person` s at a page size of 10 would simply look something like this: .Paging access to Person entities ==== @@ -139,17 +139,17 @@ public interface PersonRepository extends PagingAndSortingRepository findByFirstname(String firstname, Pageable pageable); <2> Person findByShippingAddresses(Address address); <3> - + Stream findAllBy(); <4> } ---- <1> The method shows a query for all people with the given lastname. The query will be derived parsing the method name for constraints which can be concatenated with `And` and `Or`. Thus the method name will result in a query expression of `{"lastname" : lastname}`. <2> Applies pagination to a query. Just equip your method signature with a `Pageable` parameter and let the method return a `Page` instance and we will automatically page the query accordingly. -<3> Shows that you can query based on properties which are not a primitive type. +<3> Shows that you can query based on properties which are not a primitive type. <4> Uses a Java 8 `Stream` which reads and converts individual elements while iterating the stream. ==== - + NOTE: Note that for version 1.0 we currently don't support referring to parameters that are mapped as `DBRef` in the domain class. @@ -328,7 +328,7 @@ public interface PersonRepository extends MongoRepository // Metric: {'geoNear' : 'person', 'near' : [x, y], 'maxDistance' : distance, // 'distanceMultiplier' : metric.multiplier, 'spherical' : true } GeoResults findByLocationNear(Point location, Distance distance); - + // Metric: {'geoNear' : 'person', 'near' : [x, y], 'minDistance' : min, // 'maxDistance' : max, 'distanceMultiplier' : metric.multiplier, // 'spherical' : true } diff --git a/src/main/asciidoc/reference/mongodb.adoc b/src/main/asciidoc/reference/mongodb.adoc index 71a2b5812b..d99353568a 100644 --- a/src/main/asciidoc/reference/mongodb.adoc +++ b/src/main/asciidoc/reference/mongodb.adoc @@ -366,7 +366,7 @@ public class MongoConfiguration { [[mongo.mongo-db-factory-xml]] === Registering a MongoDbFactory instance using XML based metadata -The mongo namespace provides a convient way to create a `SimpleMongoDbFactory` as compared to using the`` namespace. Simple usage is shown below +The mongo namespace provides a convient way to create a `SimpleMongoDbFactory` as compared to using the `` namespace. Simple usage is shown below [source,xml] ---- @@ -643,21 +643,21 @@ NOTE: This example is meant to show the use of save, update and remove operation The query syntax used in the example is explained in more detail in the section <>. [[mongo-template.id-handling]] -=== How the '_id' field is handled in the mapping layer +=== How the `_id` field is handled in the mapping layer -MongoDB requires that you have an '_id' field for all documents. If you don't provide one the driver will assign a `ObjectId` with a generated value. When using the `MongoMappingConverter` there are certain rules that govern how properties from the Java class is mapped to this '_id' field. +MongoDB requires that you have an `_id` field for all documents. If you don't provide one the driver will assign a `ObjectId` with a generated value. When using the `MongoMappingConverter` there are certain rules that govern how properties from the Java class is mapped to this `_id` field. -The following outlines what property will be mapped to the '_id' document field: +The following outlines what property will be mapped to the `_id` document field: -* A property or field annotated with `@Id` (`org.springframework.data.annotation.Id`) will be mapped to the '_id' field. -* A property or field without an annotation but named `id` will be mapped to the '_id' field. +* A property or field annotated with `@Id` (`org.springframework.data.annotation.Id`) will be mapped to the `_id` field. +* A property or field without an annotation but named `id` will be mapped to the `_id` field. The following outlines what type conversion, if any, will be done on the property mapped to the _id document field when using the `MappingMongoConverter`, the default for `MongoTemplate`. * An id property or field declared as a String in the Java class will be converted to and stored as an `ObjectId` if possible using a Spring `Converter`. Valid conversion rules are delegated to the MongoDB Java driver. If it cannot be converted to an ObjectId, then the value will be stored as a string in the database. * An id property or field declared as `BigInteger` in the Java class will be converted to and stored as an `ObjectId` using a Spring `Converter`. -If no field or property specified above is present in the Java class then an implicit '_id' file will be generated by the driver but not mapped to a property or field of the Java class. +If no field or property specified above is present in the Java class then an implicit `_id` file will be generated by the driver but not mapped to a property or field of the Java class. When querying and updating `MongoTemplate` will use the converter to handle conversions of the `Query` and `Update` objects that correspond to the above rules for saving documents so field names and types used in your queries will be able to match what is in your domain classes. @@ -815,7 +815,7 @@ There are two ways to manage the collection name that is used for operating on t The MongoDB driver supports inserting a collection of documents in one operation. The methods in the MongoOperations interface that support this functionality are listed below * *insert* inserts an object. If there is an existing document with the same id then an error is generated. -* *insertAll* takes a `Collection `of objects as the first parameter. This method inspects each object and inserts it to the appropriate collection based on the rules specified above. +* *insertAll* takes a `Collection` of objects as the first parameter. This method inspects each object and inserts it to the appropriate collection based on the rules specified above. * *save* saves the object overwriting any object that might exist with the same id. [[mongo-template.save-insert.batch]] @@ -823,12 +823,12 @@ The MongoDB driver supports inserting a collection of documents in one operation The MongoDB driver supports inserting a collection of documents in one operation. The methods in the MongoOperations interface that support this functionality are listed below -* *insert*` methods that take a `Collection` as the first argument. This inserts a list of objects in a single batch write to the database. +* *insert* methods that take a `Collection` as the first argument. This inserts a list of objects in a single batch write to the database. [[mongodb-template-update]] === Updating documents in a collection -For updates we can elect to update the first document found using `MongoOperation`'s method `updateFirst` or we can update all documents that were found to match the query using the method `updateMulti`. Here is an example of an update of all SAVINGS accounts where we are adding a one time $50.00 bonus to the balance using the `$inc` operator. +For updates we can elect to update the first document found using `MongoOperation` 's method `updateFirst` or we can update all documents that were found to match the query using the method `updateMulti`. Here is an example of an update of all SAVINGS accounts where we are adding a one time $50.00 bonus to the balance using the `$inc` operator. .Updating documents using the MongoTemplate ==== @@ -1051,7 +1051,7 @@ There are also methods on the Criteria class for geospatial queries. Here is a l * `Criteria` *within* `(Circle circle)` Creates a geospatial criterion using `$geoWithin $center` operators. * `Criteria` *within* `(Box box)` Creates a geospatial criterion using a `$geoWithin $box` operation. * `Criteria` *withinSphere* `(Circle circle)` Creates a geospatial criterion using `$geoWithin $center` operators. -* `Criteria` *near* `(Point point)` Creates a geospatial criterion using a `$near `operation +* `Criteria` *near* `(Point point)` Creates a geospatial criterion using a `$near` operation * `Criteria` *nearSphere* `(Point point)` Creates a geospatial criterion using `$nearSphere$center` operations. This is only available for MongoDB 1.7 and higher. * `Criteria` *minDistance* `(double minDistance)` Creates a geospatial criterion using the `$minDistance` operation, for use with $near. * `Criteria` *maxDistance* `(double maxDistance)` Creates a geospatial criterion using the `$maxDistance` operation, for use with $near. @@ -1391,7 +1391,7 @@ Executing this will result in a collection as shown below. { "_id" : "d", "value" : 1 } ---- -Assuming that the map and reduce functions are located in map.js and reduce.js and bundled in your jar so they are available on the classpath, you can execute a map-reduce operation and obtain the results as shown below +Assuming that the map and reduce functions are located in `map.js` and `reduce.js` and bundled in your jar so they are available on the classpath, you can execute a map-reduce operation and obtain the results as shown below [source,java] ---- @@ -1499,7 +1499,7 @@ Spring provides integration with MongoDB's group operation by providing methods [[mongo.group.example]] === Example Usage -In order to understand how group operations work the following example is used, which is somewhat artificial. For a more realistic example consult the book 'MongoDB - The definitive guide'. A collection named "group_test_collection" created with the following rows. +In order to understand how group operations work the following example is used, which is somewhat artificial. For a more realistic example consult the book 'MongoDB - The definitive guide'. A collection named `group_test_collection` created with the following rows. [source] ---- @@ -1511,7 +1511,7 @@ In order to understand how group operations work the following example is used, { "_id" : ObjectId("4ec1d25d41421e2015da64f6"), "x" : 3 } ---- -We would like to group by the only field in each row, the 'x' field and aggregate the number of times each specific value of 'x' occurs. To do this we need to create an initial document that contains our count variable and also a reduce function which will increment it each time it is encountered. The Java code to execute the group operation is shown below +We would like to group by the only field in each row, the `x` field and aggregate the number of times each specific value of `x` occurs. To do this we need to create an initial document that contains our count variable and also a reduce function which will increment it each time it is encountered. The Java code to execute the group operation is shown below [source,java] ---- @@ -1670,7 +1670,7 @@ Note that the aggregation operations not listed here are currently not supported [[mongo.aggregation.projection]] === Projection Expressions -Projection expressions are used to define the fields that are the outcome of a particular aggregation step. Projection expressions can be defined via the `project` method of the `Aggregate` class either by passing a list of `String`s or an aggregation framework `Fields` object. The projection can be extended with additional fields through a fluent API via the `and(String)` method and aliased via the `as(String)` method. +Projection expressions are used to define the fields that are the outcome of a particular aggregation step. Projection expressions can be defined via the `project` method of the `Aggregate` class either by passing a list of `String` 's or an aggregation framework `Fields` object. The projection can be extended with additional fields through a fluent API via the `and(String)` method and aliased via the `as(String)` method. Note that one can also define fields with aliases via the static factory method `Fields.field` of the aggregation framework that can then be used to construct a new `Fields` instance. .Projection expression examples @@ -1814,7 +1814,7 @@ ZipInfoStats firstZipInfoStats = result.getMappedResults().get(0); ---- * The class `ZipInfo` maps the structure of the given input-collection. The class `ZipInfoStats` defines the structure in the desired output format. -* As a first step we use the `group` operation to define a group from the input-collection. The grouping criteria is the combination of the fields `"state"` and `"city" `which forms the id structure of the group. We aggregate the value of the `"population"` property from the grouped elements with by using the `sum` operator saving the result in the field `"pop"`. +* As a first step we use the `group` operation to define a group from the input-collection. The grouping criteria is the combination of the fields `"state"` and `"city"` which forms the id structure of the group. We aggregate the value of the `"population"` property from the grouped elements with by using the `sum` operator saving the result in the field `"pop"`. * In a second step we use the `sort` operation to sort the intermediate-result by the fields `"pop"`, `"state"` and `"city"` in ascending order, such that the smallest city is at the top and the biggest city is at the bottom of the result. Note that the sorting on "state" and `"city"` is implicitly performed against the group id fields which Spring Data MongoDB took care of. * In the third step we use a `group` operation again to group the intermediate result by `"state"`. Note that `"state"` again implicitly references an group-id field. We select the name and the population count of the biggest and smallest city with calls to the `last(…)` and `first(...)` operator respectively via the `project` operation. * As the forth step we select the `"state"` field from the previous `group` operation. Note that `"state"` again implicitly references an group-id field. As we do not want an implicit generated id to appear, we exclude the id from the previous operation via `and(previousOperation()).exclude()`. As we want to populate the nested `City` structures in our output-class accordingly we have to emit appropriate sub-documents with the nested method. @@ -2011,7 +2011,7 @@ public class PersonReadConverter implements Converter { [[mongo.custom-converters.xml]] === Registering Spring Converters with the MongoConverter -The Mongo Spring namespace provides a convenience way to register Spring `Converter`s with the `MappingMongoConverter`. The configuration snippet below shows how to manually register converter beans as well as configuring the wrapping `MappingMongoConverter` into a `MongoTemplate`. +The Mongo Spring namespace provides a convenience way to register Spring `Converter` s with the `MappingMongoConverter`. The configuration snippet below shows how to manually register converter beans as well as configuring the wrapping `MappingMongoConverter` into a `MongoTemplate`. [source,xml] ---- @@ -2221,7 +2221,7 @@ Here is a list of execute callback methods. * ` T` *execute* `(String collectionName, DbCallback action)` Executes a DbCallback on the collection of the given name translating any exceptions as necessary. -* ` T` *executeInSession* `(DbCallback action) ` Executes the given DbCallback within the same connection to the database so as to ensure consistency in a write heavy environment where you may read the data that you wrote. +* ` T` *executeInSession* `(DbCallback action)` Executes the given DbCallback within the same connection to the database so as to ensure consistency in a write heavy environment where you may read the data that you wrote. Here is an example that uses the `CollectionCallback` to return information about an index From 17f8ae5fa3936285fb82c65ddf457fe7b2dace57 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 26 Apr 2016 08:54:02 +0200 Subject: [PATCH 5/6] DATAMONGO-1412 - Document UUID mapping. --- src/main/asciidoc/reference/mapping.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/asciidoc/reference/mapping.adoc b/src/main/asciidoc/reference/mapping.adoc index ac0d4dd627..9522fbe29d 100644 --- a/src/main/asciidoc/reference/mapping.adoc +++ b/src/main/asciidoc/reference/mapping.adoc @@ -98,6 +98,10 @@ In addition to these types, Spring Data MongoDB provides a set of built-in conve | native | `{"bin" : { "$binary" : "AQIDBA==", "$type" : "00" }}` +| `java.util.UUID` (Legacy UUID) +| native +| `{"uuid" : { "$binary" : "MEaf1CFQ6lSphaa3b9AtlA==", "$type" : "03" }}` + | `Date` | native | `{"date" : ISODate("2019-11-12T23:00:00.809Z")}` From 8f80d06c6186b52799a0a617247ed0b536f19773 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 2 May 2016 10:44:29 +0200 Subject: [PATCH 6/6] DATAMONGO-1404 - Adopt review feedback. Rename MongoDB representation to sample. Represent Point within a field. Add missing whitespaces to improve readability. --- src/main/asciidoc/reference/mapping.adoc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/asciidoc/reference/mapping.adoc b/src/main/asciidoc/reference/mapping.adoc index 9522fbe29d..865bdb685e 100644 --- a/src/main/asciidoc/reference/mapping.adoc +++ b/src/main/asciidoc/reference/mapping.adoc @@ -70,7 +70,7 @@ In addition to these types, Spring Data MongoDB provides a set of built-in conve |=== | Type | Type conversion -| MongoDB representation +| Sample | `String` | native @@ -205,7 +205,7 @@ calling `get()` before the actual conversion | `Point` | converter -| `{ "x" : 1.0 , "y" : 2.0}` +| `{"point" : { "x" : 1.0 , "y" : 2.0}}` | `GeoJsonPoint` | converter @@ -213,7 +213,7 @@ calling `get()` before the actual conversion | `GeoJsonMultiPoint` | converter -| `{"geoJsonLineString":{"type":"MultiPoint", "coordinates": [ [0,0],[0,1],[1,1] ] }}` +| `{"geoJsonLineString" : {"type":"MultiPoint", "coordinates": [ [ 0 , 0 ], [ 0 , 1 ], [ 1 , 1 ] ] }}` | `Sphere` | converter @@ -221,24 +221,24 @@ calling `get()` before the actual conversion | `GeoJsonPolygon` | converter -| `{"polygon" : { "type" : "Polygon", "coordinates" : [[ [ 0 , 0 ] , [ 3 , 6 ] , [ 6 , 1 ] , [ 0 , 0 ] ]] }}` +| `{"polygon" : { "type" : "Polygon", "coordinates" : [[ [ 0 , 0 ], [ 3 , 6 ], [ 6 , 1 ], [ 0 , 0 ] ]] }}` | `GeoJsonMultiPolygon` | converter | `{"geoJsonMultiPolygon" : { "type" : "MultiPolygon", "coordinates" : [ - [ [ [ -73.958, 40.8003 ], [ -73.9498, 40.7968 ], ] ], - [ [ [ -73.9737, 40.7648 ], [ -73.958, 40.8003 ] ] ] + [ [ [ -73.958 , 40.8003 ] , [ -73.9498 , 40.7968 ] ] ], + [ [ [ -73.973 , 40.7648 ] , [ -73.9588 , 40.8003 ] ] ] ] }}` | `GeoJsonLineString` | converter -| `{ "geoJsonLineString" : {"type" : "LineString", "coordinates" : [ [ 40, 5 ], [ 41, 6 ] ]}}` +| `{ "geoJsonLineString" : { "type" : "LineString", "coordinates" : [ [ 40 , 5 ], [ 41 , 6 ] ] }}` | `GeoJsonMultiLineString` | converter -| `{"geoJsonLineString" : {"type": "MultiLineString", coordinates: [ - [ [ -73.97162, 40.78205 ], [ -73.96374, 40.77715 ] ], - [ [ -73.97880, 40.77247 ], [ -73.97036, 40.76811 ] ] +| `{"geoJsonLineString" : { "type" : "MultiLineString", coordinates: [ + [ [ -73.97162 , 40.78205 ], [ -73.96374 , 40.77715 ] ], + [ [ -73.97880 , 40.77247 ], [ -73.97036 , 40.76811 ] ] ] }}` |===