如何在进行批量更新时有条件地包含 CreationDate ($setOnInsert with $set creates error)
How to conditionally include CreationDate when making a bulk upsert ($setOnInsert with $set creates error)
我是 mongoDB 的初学者,我正在尝试更新或创建一个非常大的产品列表。数据库中已存在的产品将有一个我不希望覆盖的“creationDate”。使用以下代码时:
public AddProductResponse add(final String trackingId, final String catalogName, final List<Product> products) {
final AddProductResponse res = new AddProductResponse();
res.products(products);
final List<WriteModel<Product>> writes = new ArrayList<>();
for (final Product product : products) {
final OffsetDateTime creationDate = OffsetDateTime.now();
product.setLastUpdate(OffsetDateTime.now());
final Bson filter = Filters.eq(Constants.PRODUCT_ID_PROPERTY, product.getId());
final Bson update = new Document("$set", product).append("$setOnInsert", new Document(Constants.PRODUCT_CREATION_DATE_PROPERTY, creationDate));
final UpdateOptions options = new UpdateOptions().upsert(true);
writes.add(new UpdateOneModel<>(filter, update, options));
}
try {
final BulkWriteResult bulkWriteResult = getCollection(trackingId, catalogName, COLLECTION_TYPE, Product.class).bulkWrite(writes, new BulkWriteOptions().ordered(false));
LOG.info("Bulk write result: {}", bulkWriteResult);
if (!bulkWriteResult.wasAcknowledged()) {
res.setSuccess(false);
res.reason(Constants.UNKNOWN_ERROR_MESSAGE);
} else {
res.setSuccess(true);
}
} catch (final Exception e) {
res.setSuccess(false);
LOG.info("Error: {}", e.getMessage());
res.setReason(e.getMessage());
}
return res;
}
我收到错误消息:“更新路径 'creationDate' 会在 'creationDate' 处产生冲突”,我理解另一个 中列出的原因,但我'我想知道是否有其他方法可以实现这一目标。此外,下面是我为确保实现功能而编写的测试。感谢您的帮助。
@Test
public void testAddProductListEndpointWithExistingProduct() throws JsonProcessingException {
final Product p = getProduct();
final String token = getToken(trackingId);
addCatalog(trackingId, catalog, null, token);
final Response addProductResponse = addProduct(trackingId, catalog, p, token);
final Document doc = getDatabase().getCollection(productsCollection).find(new BasicDBObject("id", p.getId()))
.first();
final List<Product> products = new ArrayList<>();
products.add(new Product().id("p1").name("Product 1").creationDate(OffsetDateTime.now().plusHours(1)).categoryHierarchies(List.of(new Category().id("id1").label("label1").type("type1"))));
products.add(new Product().id("p2").name("Product 2").categoryHierarchies(List.of(new Category().id("id1").label("label1").type("type1"))));
products.add(new Product().id("p3").name("Product 3").categoryHierarchies(List.of(new Category().id("id1").label("label1").type("type1"))));
final Response addProductResponse2 = addProducts(trackingId, catalog, products, token);
final Document doc2 = getDatabase().getCollection(productsCollection).find(new BasicDBObject("id", "p1")).first();
//creation date of existing product should not be overwritten
Assert.assertTrue(doc.get("creationDate").equals(doc2.get("creationDate")));
}
如果您希望使用批量和产品列表来更新产品,那么如果您的列表中的每个产品尚不存在,则将被插入,并且如果存在则将覆盖现有文档,但不creationDate
属性就是直接在product
下,可以这样:
如果创建日期在您的产品下,您不能同时 $set
它在产品和 $setOnInsert
下,因此如果您的产品结构是:
product: {
creationDate: ISODate,
propX: 'a',
propY: {propZ: 2, propT: 4, propA: ['A', 'B']}
}
你的代码应该是这样的:
final Bson update = new Document("$set", 'product.propX', 'product.propY')
.append("$setOnInsert", new Document(Constants.PRODUCT_CREATION_DATE_PROPERTY, creationDate));
请注意,批量操作是在作为查询执行之前使用您的代码编写的。这意味着您可以使用循环来更新批量的 $set
部分,以便将所有属性直接添加到 product
下,从您的产品列表到您的 $set
子句。
您可以在 playground, in the 上看到类似问题。
我是 mongoDB 的初学者,我正在尝试更新或创建一个非常大的产品列表。数据库中已存在的产品将有一个我不希望覆盖的“creationDate”。使用以下代码时:
public AddProductResponse add(final String trackingId, final String catalogName, final List<Product> products) {
final AddProductResponse res = new AddProductResponse();
res.products(products);
final List<WriteModel<Product>> writes = new ArrayList<>();
for (final Product product : products) {
final OffsetDateTime creationDate = OffsetDateTime.now();
product.setLastUpdate(OffsetDateTime.now());
final Bson filter = Filters.eq(Constants.PRODUCT_ID_PROPERTY, product.getId());
final Bson update = new Document("$set", product).append("$setOnInsert", new Document(Constants.PRODUCT_CREATION_DATE_PROPERTY, creationDate));
final UpdateOptions options = new UpdateOptions().upsert(true);
writes.add(new UpdateOneModel<>(filter, update, options));
}
try {
final BulkWriteResult bulkWriteResult = getCollection(trackingId, catalogName, COLLECTION_TYPE, Product.class).bulkWrite(writes, new BulkWriteOptions().ordered(false));
LOG.info("Bulk write result: {}", bulkWriteResult);
if (!bulkWriteResult.wasAcknowledged()) {
res.setSuccess(false);
res.reason(Constants.UNKNOWN_ERROR_MESSAGE);
} else {
res.setSuccess(true);
}
} catch (final Exception e) {
res.setSuccess(false);
LOG.info("Error: {}", e.getMessage());
res.setReason(e.getMessage());
}
return res;
}
我收到错误消息:“更新路径 'creationDate' 会在 'creationDate' 处产生冲突”,我理解另一个
@Test
public void testAddProductListEndpointWithExistingProduct() throws JsonProcessingException {
final Product p = getProduct();
final String token = getToken(trackingId);
addCatalog(trackingId, catalog, null, token);
final Response addProductResponse = addProduct(trackingId, catalog, p, token);
final Document doc = getDatabase().getCollection(productsCollection).find(new BasicDBObject("id", p.getId()))
.first();
final List<Product> products = new ArrayList<>();
products.add(new Product().id("p1").name("Product 1").creationDate(OffsetDateTime.now().plusHours(1)).categoryHierarchies(List.of(new Category().id("id1").label("label1").type("type1"))));
products.add(new Product().id("p2").name("Product 2").categoryHierarchies(List.of(new Category().id("id1").label("label1").type("type1"))));
products.add(new Product().id("p3").name("Product 3").categoryHierarchies(List.of(new Category().id("id1").label("label1").type("type1"))));
final Response addProductResponse2 = addProducts(trackingId, catalog, products, token);
final Document doc2 = getDatabase().getCollection(productsCollection).find(new BasicDBObject("id", "p1")).first();
//creation date of existing product should not be overwritten
Assert.assertTrue(doc.get("creationDate").equals(doc2.get("creationDate")));
}
如果您希望使用批量和产品列表来更新产品,那么如果您的列表中的每个产品尚不存在,则将被插入,并且如果存在则将覆盖现有文档,但不creationDate
属性就是直接在product
下,可以这样:
如果创建日期在您的产品下,您不能同时 $set
它在产品和 $setOnInsert
下,因此如果您的产品结构是:
product: {
creationDate: ISODate,
propX: 'a',
propY: {propZ: 2, propT: 4, propA: ['A', 'B']}
}
你的代码应该是这样的:
final Bson update = new Document("$set", 'product.propX', 'product.propY')
.append("$setOnInsert", new Document(Constants.PRODUCT_CREATION_DATE_PROPERTY, creationDate));
请注意,批量操作是在作为查询执行之前使用您的代码编写的。这意味着您可以使用循环来更新批量的 $set
部分,以便将所有属性直接添加到 product
下,从您的产品列表到您的 $set
子句。
您可以在 playground, in the