项目中出现了这样一个问题,内嵌唯一索引不生效导致出现不合预期的数据。

找下原因。

document如下:

@Data
@Document(collection = "out")
@CompoundIndexes({
        @CompoundIndex(name = "inner_unique", def = "{'inner.key':1}", unique = true)
})
public class OutDocument {
    @Id
    private String id;

    private String code;

    private String name;

    private List<InnerDocument> inner;
}
@Data
@AllArgsConstructor
public class InnerDocument {

    private String key;

    private String value;
}

测试方法:

@Test
    public void saveOrUpdate() {

        OutDocument outDocument = new OutDocument();
        outDocument.setCode("QWER001");
        outDocument.setName("测试索引");

        List<InnerDocument> innerDocuments = Arrays.asList(new InnerDocument("001", "潘森"), new InnerDocument("002", "妖姬"));

        outDocument.setInner(innerDocuments);

        outDocumentRepository.save(outDocument).subscribe(System.out::println);

    }

执行第一遍,看下数据:

{
    "_id": ObjectId("5c2dc8c846ce5e00cc26239c"),
    "code": "QWER001",
    "name": "测试索引",
    "inner": [
        {
            "key": "001",
            "value": "潘森"
        },
        {
            "key": "002",
            "value": "妖姬"
        }
    ],
    "_class": "com.paranoia.webfluxreactive.collection.index.OutDocument"
}

再次执行这个插入方法:

Caused by: com.mongodb.MongoWriteException: E11000 duplicate key error collection: test.out index: inner_unique dup key: { : "001" }

索引生效。

到这里我们没有发现什么问题,姿势正确。

那么,换一个姿势,修改inner。

@Test
    public void addToInnerIndex() {

        Mono<OutDocument> documentMono = outDocumentRepository.findById("5c2dc8c846ce5e00cc26239c")
                .map(result -> {
                    List<InnerDocument> inner = result.getInner();
                    inner.add(new InnerDocument("001", "潘森的爸爸"));
                    return result;
                })
                .flatMap(newOut -> outDocumentRepository.save(newOut));

        documentMono.block();
    }

看下数据:

{
    "_id": ObjectId("5c2dc8c846ce5e00cc26239c"),
    "code": "QWER001",
    "name": "测试索引",
    "inner": [
        {
            "key": "001",
            "value": "潘森"
        },
        {
            "key": "002",
            "value": "妖姬"
        },
        {
            "key": "001",
            "value": "潘森的爸爸"
        }
    ],
    "_class": "com.paranoia.webfluxreactive.collection.index.OutDocument"

发现索引并没有生效,这说明这个姿势不对,不用jpa ,试一下template

@Test
    public void addToInnerIndexTryTemplate() {

        Query query = new Query(Criteria.where("code").is("QWER001"));
        Update update = new Update();
        update.addToSet("inner", new InnerDocument("001", "潘森的爷爷"));

        reactiveMongoTemplate.updateMulti(query, update, OutDocument.class).block();
    }

看下数据,

{
    "_id": ObjectId("5c2dc8c846ce5e00cc26239c"),
    "code": "QWER001",
    "name": "测试索引",
    "inner": [
        {
            "key": "001",
            "value": "潘森"
        },
        {
            "key": "002",
            "value": "妖姬"
        },
        {
            "key": "001",
            "value": "潘森的爸爸"
        },
        {
            "key": "001",
            "value": "潘森的爷爷"
        }
    ],
    "_class": "com.paranoia.webfluxreactive.collection.index.OutDocument"
}

发现还是没有生效,看来这两种姿势都不会在修改内嵌数据的时候去适配索引。那么,这种情况到底该采用一个什么姿势?