Skip to content

Add support for mapping document fields with dot (.) in the field name #4512

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
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.2.0-SNAPSHOT</version>
<version>4.2.x-4464-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Spring Data MongoDB</name>
Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb-benchmarks/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.2.0-SNAPSHOT</version>
<version>4.2.x-4464-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.2.0-SNAPSHOT</version>
<version>4.2.x-4464-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-mongodb/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb-parent</artifactId>
<version>4.2.0-SNAPSHOT</version>
<version>4.2.x-4464-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.dao.DataAccessException;
import org.springframework.data.mongodb.core.mapping.FieldName;
import org.springframework.data.mongodb.core.script.ExecutableMongoScript;
import org.springframework.data.mongodb.core.script.NamedMongoScript;
import org.springframework.util.Assert;
Expand Down Expand Up @@ -123,7 +124,8 @@ public boolean exists(String scriptName) {

Assert.hasText(scriptName, "ScriptName must not be null or empty");

return mongoOperations.exists(query(where("_id").is(scriptName)), NamedMongoScript.class, SCRIPT_COLLECTION_NAME);
return mongoOperations.exists(query(where(FieldName.ID.name()).is(scriptName)), NamedMongoScript.class,
SCRIPT_COLLECTION_NAME);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.springframework.data.mongodb.core.convert.MongoJsonSchemaMapper;
import org.springframework.data.mongodb.core.convert.MongoWriter;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.mapping.FieldName;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
Expand Down Expand Up @@ -79,7 +80,7 @@
*/
class EntityOperations {

private static final String ID_FIELD = "_id";
private static final String ID_FIELD = FieldName.ID.name();

private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> context;
private final QueryMapper queryMapper;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.data.mongodb.core.mapping.FieldName;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.data.util.StreamUtils;
Expand All @@ -33,7 +34,7 @@
*/
public class MappedDocument {

private static final String ID_FIELD = "_id";
private static final String ID_FIELD = FieldName.ID.name();
private static final Document ID_ONLY_PROJECTION = new Document(ID_FIELD, 1);

private final Document document;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.convert.QueryMapper;
import org.springframework.data.mongodb.core.convert.UpdateMapper;
import org.springframework.data.mongodb.core.mapping.FieldName;
import org.springframework.data.mongodb.core.mapping.MongoId;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
Expand Down Expand Up @@ -849,7 +850,7 @@ private boolean shardedById(MongoPersistentEntity<?> domainType) {
}

String key = shardKey.getPropertyNames().iterator().next();
if ("_id".equals(key)) {
if (FieldName.ID.name().equals(key)) {
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import static org.springframework.data.mongodb.core.query.SerializationUtils.*;

import org.springframework.data.mongodb.core.CollectionPreparerSupport.CollectionPreparerDelegate;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.function.Tuple2;
Expand Down Expand Up @@ -104,6 +103,7 @@
import org.springframework.data.mongodb.core.index.MongoMappingEventPublisher;
import org.springframework.data.mongodb.core.index.ReactiveIndexOperations;
import org.springframework.data.mongodb.core.index.ReactiveMongoPersistentEntityIndexCreator;
import org.springframework.data.mongodb.core.mapping.FieldName;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
Expand Down Expand Up @@ -133,7 +133,16 @@
import com.mongodb.MongoException;
import com.mongodb.ReadPreference;
import com.mongodb.WriteConcern;
import com.mongodb.client.model.*;
import com.mongodb.client.model.CountOptions;
import com.mongodb.client.model.CreateCollectionOptions;
import com.mongodb.client.model.CreateViewOptions;
import com.mongodb.client.model.DeleteOptions;
import com.mongodb.client.model.EstimatedDocumentCountOptions;
import com.mongodb.client.model.FindOneAndDeleteOptions;
import com.mongodb.client.model.FindOneAndReplaceOptions;
import com.mongodb.client.model.FindOneAndUpdateOptions;
import com.mongodb.client.model.ReturnDocument;
import com.mongodb.client.model.UpdateOptions;
import com.mongodb.client.model.changestream.FullDocument;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.InsertOneResult;
Expand Down Expand Up @@ -826,7 +835,7 @@ public Mono<Boolean> exists(Query query, @Nullable Class<?> entityClass, String
Document filter = queryContext.getMappedQuery(entityClass, this::getPersistentEntity);

FindPublisher<Document> findPublisher = collectionPreparer.prepare(collection).find(filter, Document.class)
.projection(new Document("_id", 1));
.projection(new Document(FieldName.ID.name(), 1));

if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("exists: %s in collection: %s", serializeToJsonSafely(filter), collectionName));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.springframework.data.mongodb.core.aggregation.MergeOperation.MergeOperationBuilder;
import org.springframework.data.mongodb.core.aggregation.ReplaceRootOperation.ReplaceRootDocumentOperationBuilder;
import org.springframework.data.mongodb.core.aggregation.ReplaceRootOperation.ReplaceRootOperationBuilder;
import org.springframework.data.mongodb.core.mapping.FieldName;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
import org.springframework.data.mongodb.core.query.NearQuery;
Expand Down Expand Up @@ -224,7 +225,7 @@ public AggregationOptions getOptions() {
* @return
*/
public static String previousOperation() {
return "_id";
return FieldName.ID.name();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.List;
import java.util.Map;

import org.springframework.data.mongodb.core.mapping.FieldName;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
Expand All @@ -40,7 +41,7 @@ public final class Fields implements Iterable<Field> {
private static final String AMBIGUOUS_EXCEPTION = "Found two fields both using '%s' as name: %s and %s; Please "
+ "customize your field definitions to get to unique field names";

public static final String UNDERSCORE_ID = "_id";
public static final String UNDERSCORE_ID = FieldName.ID.name();
public static final String UNDERSCORE_ID_REF = "$_id";

private final List<Field> fields;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;

import org.bson.Document;
import org.springframework.util.Assert;
Expand Down Expand Up @@ -52,6 +53,41 @@ public static ObjectOperatorFactory valueOf(AggregationExpression expression) {
return new ObjectOperatorFactory(expression);
}

/**
* Use the value from the given {@link SystemVariable} as input for the target {@link AggregationExpression expression}.
*
* @param variable the {@link SystemVariable} to use (eg. {@link SystemVariable#ROOT}.
* @return new instance of {@link ObjectOperatorFactory}.
* @since 4.2
*/
public static ObjectOperatorFactory valueOf(SystemVariable variable) {
return new ObjectOperatorFactory(Fields.field(variable.getName(), variable.getTarget()));
}

/**
* Get the value of the field with given name from the {@literal $$CURRENT} object.
* Short version for {@code ObjectOperators.valueOf("$$CURRENT").getField(fieldName)}.
*
* @param fieldName the field name.
* @return new instance of {@link AggregationExpression}.
* @since 4.2
*/
public static AggregationExpression getValueOf(String fieldName) {
return new ObjectOperatorFactory(SystemVariable.CURRENT).getField(fieldName);
}

/**
* Set the value of the field with given name on the {@literal $$CURRENT} object.
* Short version for {@code ObjectOperators.valueOf($$CURRENT).setField(fieldName).toValue(value)}.
*
* @param fieldName the field name.
* @return new instance of {@link AggregationExpression}.
* @since 4.2
*/
public static AggregationExpression setValueTo(String fieldName, Object value) {
return new ObjectOperatorFactory(SystemVariable.CURRENT).setField(fieldName).toValue(value);
}

/**
* @author Christoph Strobl
*/
Expand Down Expand Up @@ -133,7 +169,7 @@ public ObjectToArray toArray() {
* @since 4.0
*/
public GetField getField(String fieldName) {
return GetField.getField(fieldName).of(value);
return GetField.getField(Fields.field(fieldName)).of(value);
}

/**
Expand All @@ -143,7 +179,7 @@ public GetField getField(String fieldName) {
* @since 4.0
*/
public SetField setField(String fieldName) {
return SetField.field(fieldName).input(value);
return SetField.field(Fields.field(fieldName)).input(value);
}

/**
Expand Down Expand Up @@ -340,7 +376,7 @@ public static GetField getField(String fieldName) {
* @return new instance of {@link GetField}.
*/
public static GetField getField(Field field) {
return getField(field.getTarget());
return new GetField(Collections.singletonMap("field", field));
}

/**
Expand Down Expand Up @@ -369,6 +405,15 @@ private GetField of(Object fieldRef) {
return new GetField(append("input", fieldRef));
}

@Override
public Document toDocument(AggregationOperationContext context) {

if(isArgumentMap() && get("field") instanceof Field field) {
return new GetField(append("field", context.getReference(field).getRaw())).toDocument(context);
}
return super.toDocument(context);
}

@Override
protected String getMongoMethod() {
return "$getField";
Expand Down Expand Up @@ -405,7 +450,7 @@ public static SetField field(String fieldName) {
* @return new instance of {@link SetField}.
*/
public static SetField field(Field field) {
return field(field.getTarget());
return new SetField(Collections.singletonMap("field", field));
}

/**
Expand Down Expand Up @@ -472,6 +517,14 @@ public SetField toValue(Object value) {
return new SetField(append("value", value));
}

@Override
public Document toDocument(AggregationOperationContext context) {
if(get("field") instanceof Field field) {
return new SetField(append("field", context.getReference(field).getRaw())).toDocument(context);
}
return super.toDocument(context);
}

@Override
protected String getMongoMethod() {
return "$setField";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bson.Document;

import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.MongoDatabaseUtils;
import org.springframework.data.mongodb.core.convert.ReferenceLoader.DocumentReferenceQuery;
import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentProperty;
import org.springframework.data.mongodb.core.mapping.FieldName;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
Expand Down Expand Up @@ -87,7 +87,8 @@ public Object resolveDbRef(MongoPersistentProperty property, @Nullable DBRef dbr

@Override
public Document fetch(DBRef dbRef) {
return getReferenceLoader().fetchOne(DocumentReferenceQuery.forSingleDocument(Filters.eq("_id", dbRef.getId())),
return getReferenceLoader().fetchOne(
DocumentReferenceQuery.forSingleDocument(Filters.eq(FieldName.ID.name(), dbRef.getId())),
ReferenceCollection.fromDBRef(dbRef));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

import org.bson.Document;
import org.bson.conversions.Bson;

import org.springframework.data.mongodb.core.mapping.FieldName;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
import org.springframework.data.mongodb.util.BsonUtils;
Expand Down Expand Up @@ -91,14 +91,8 @@ public void putAll(Document source) {
public void put(MongoPersistentProperty prop, @Nullable Object value) {

Assert.notNull(prop, "MongoPersistentProperty must not be null");
String fieldName = getFieldName(prop);

if (!fieldName.contains(".")) {
BsonUtils.addToMap(document, fieldName, value);
return;
}

Iterator<String> parts = Arrays.asList(fieldName.split("\\.")).iterator();
Iterator<String> parts = Arrays.asList(prop.getMongoField().getName().parts()).iterator();
Bson document = this.document;

while (parts.hasNext()) {
Expand Down Expand Up @@ -135,7 +129,7 @@ public Object get(MongoPersistentProperty property) {
*/
@Nullable
public Object getRawId(MongoPersistentEntity<?> entity) {
return entity.hasIdProperty() ? get(entity.getRequiredIdProperty()) : BsonUtils.get(document, "_id");
return entity.hasIdProperty() ? get(entity.getRequiredIdProperty()) : BsonUtils.get(document, FieldName.ID.name());
}

/**
Expand All @@ -153,8 +147,8 @@ public boolean hasValue(MongoPersistentProperty property) {
return BsonUtils.hasValue(document, getFieldName(property));
}

String getFieldName(MongoPersistentProperty prop) {
return prop.getFieldName();
FieldName getFieldName(MongoPersistentProperty prop) {
return prop.getMongoField().getName();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.BeanWrapperPropertyAccessorFactory;
import org.springframework.data.mongodb.core.mapping.DocumentPointer;
import org.springframework.data.mongodb.core.mapping.FieldName;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;

Expand Down Expand Up @@ -232,7 +233,7 @@ Object updatePlaceholders(org.bson.Document source, org.bson.Document target,
attribute = attribute.substring(attribute.lastIndexOf('.') + 1);
}

String fieldName = entry.getKey().equals("_id") ? "id" : entry.getKey();
String fieldName = entry.getKey().equals(FieldName.ID.name()) ? "id" : entry.getKey();
if (!fieldName.contains(".")) {

Object targetValue = propertyAccessor.getProperty(persistentEntity.getPersistentProperty(fieldName));
Expand Down
Loading