当前位置: 首页 > 知识库问答 >
问题:

Mongodb迁移导致重复的密钥

杨良才
2023-03-14

在一个老项目中,我们试图从基本的spring迁移到spring boot 2.3.1。为此,因为我们有一个mongo数据库,所以我们必须从编写这段代码的spring-data-mongodb:1.10.18迁移:

DBCollection contextCollection = this.mongoTemplate.getCollection("productStock");
BulkWriteOperation builder = contextCollection.initializeUnorderedBulkOperation();
StockType stockItem = stockMessage.getStockItem();

final BasicDBObject id = new BasicDBObject("storeID", stockItem.getStoreID()).append("productID", stockItem.getProductID());
BulkWriteRequestBuilder bulkWriteRequestBuilder = builder.find(new BasicDBObject("_id", id));
HashMap<String, Object> stock = new HashMap<>();
Date currentDate = Calendar.getInstance().getTime();

stock.put("value", stockItem.getValue());
if (stockItem.getAssociateDate() != null) {
    stock.put("associateDate", stockItem.getAssociateDate());
}

if (stockItem.getLastAccessDateSource() != null) {
    stock.put("lastAccessDateSource", stockItem.getLastAccessDateSource());

    // check
    BasicDBObject ltLast = new BasicDBObject("$lt", stockItem.getLastAccessDateSource());
    BasicDBList dbList = new BasicDBList();
    dbList.add(new BasicDBObject(stockItem.getStockCategory() + ".lastAccessDateSource", ltLast));
    dbList.add(new BasicDBObject(stockItem.getStockCategory() + ".lastAccessDateSource", null));
    bulkWriteRequestBuilder = builder.find(new BasicDBObject("_id", id).append("$or", dbList));
} else {
    stock.put("lastAccessDateSource", currentDate);
}

stock.put("lastUpdateDate", currentDate);
BasicDBObject set = new BasicDBObject(stockItem.getStockCategory(), new Document(stock));
bulkWriteRequestBuilder.upsert().updateOne(new BasicDBObject("$set", set));
builder.execute();

到spring-data-mongodb:3.0.1.RELEASE与此更新的代码

Map<String, List<StockType>> mapMultiUpdate = new HashMap<>();
StockType stockItem = stockMessage.getStockItem();

final Document id = new Document("storeID", stockItem.getStoreID()).append("productID", stockItem.getProductID());
HashMap<String, Object> stock = new HashMap<>();
Date currentDate = Calendar.getInstance().getTime();
Document searchQuery = new Document("_id", id).append("$or", dbList);
stock.put("value", stockItem.getValue());
if (stockItem.getAssociateDate() != null) {
    stock.put("associateDate", stockItem.getAssociateDate());
}

if (stockItem.getLastAccessDateSource() != null) {
    stock.put("lastAccessDateSource", stockItem.getLastAccessDateSource());

    // check
    Document ltLast = new Document("$lt", stockItem.getLastAccessDateSource());
    List<Document> dbList = Lists.newArrayList();
    dbList.add(new Document(stockItem.getStockCategory() + ".lastAccessDateSource", ltLast));
    dbList.add(new Document(stockItem.getStockCategory() + ".lastAccessDateSource", null));
} else {
    stock.put("lastAccessDateSource", currentDate);
}


//Bulk write options
BulkWriteOptions bulkWriteOptions = new BulkWriteOptions();
bulkWriteOptions.ordered(false);
bulkWriteOptions.bypassDocumentValidation(true);

MongoCollection<Document> mongoCollection = this.mongoTemplate.getCollection("productStoreStock");
mongoCollection.bulkWrite(updateDocuments, bulkWriteOptions);

但是当新代码在已经存在的对象上执行时,我们得到一个重复的键错误

com.mongodb.MongoBulkWriteException: Bulk write operation error on server localhost:27017. Write errors: [BulkWriteError{index=0, code=11000, message='E11000 duplicate key error collection: test.productStoreStock index: _id_ dup key: { : { storeID: 400, productID: 100000 } }', details={}}]. 

我们还从 mongo-java-driver:3.6.4 切换到 mongodb-driver-sync:4.0.4

编辑:

此错误在测试阶段的第 3 步,在空数据库/集合上引发。步骤:

    在特定
  • 日期使用产品上的一个库存启动收集
  • 检查基数的值
  • 在 Java 中修改股票的价值,但不修改日期并尝试更新它
  • 检查值仍然是第一个,因为 mongo 查询上的 LT 过滤器

我们从未达到检查值,在迁移之前,此测试一切都很好

共有2个答案

王庆
2023-03-14

Mongo没有更新,当没有找到匹配项时,它正在更新(插入新行)。

秦景同
2023-03-14
test.productStoreStock index: _id_ dup key: { : { storeID: 400, productID: 100000 } }', details={}}

看起来您正在用自己的“构造”id替换内部id字段。这不是一件好事。让mongo创建它自己的id,这些id保证在使用中是唯一的..永远不会重复。将您自己的companyId作为一个附加字段没有问题,但是替换mongodbs的auto generated _id字段是危险的...正如你所发现的。

 类似资料:
  • 我正在将我的应用程序从PrimeFaces 3.5.18 Mojarra 2.1.26移植到PrimeFaces 4.0.2 Mojarra 2.2.4。 当我重新启动服务器时,我得到一个ViewExpiredException。 服务器日志包含以下内容:

  • 我有一个用于java程序的库。 它包含下一行: 它在java8上运行正常,但在我尝试在java11上启动它之后,我得到了ClassCastException JAVAClassCastException:类jdk。内部的加载器。ClassLoaders$AppClassLoader不能强制转换为java类。网URLClassLoader 有可能解决这个pb而不修改库吗?AFAIK,Java应该向下

  • 我的WP站点目前在PHP5.6上,但是当更新到PHP7时,我得到了以下致命消息和死亡的白色屏幕。 致命错误:未捕获错误:调用/home/s7280o8m/public_html/wp includes/wp db.php:1568堆栈跟踪:#0/home/s7280o8m/public_html/wp includes/wp db.php(658):wpdb- F.Y.I.: > 运行PHP7兼容

  • 我有以下错误。有人在理解为什么? PHP工匠迁移 创建_users_table.php

  • 在使用可重复迁移时,我观察到一些奇怪的飞行路线行为。文件指出: 在一次迁移运行中,可重复迁移始终在所有挂起的版本化迁移执行完毕后最后应用。 但在我的例子中,可重复迁移(正在重新创建一个DB视图)似乎失败了,因为它是在版本化迁移之前执行的。 迁移前的Flyway信息数据:

  • 报价飞行路线文件https://flywaydb.org/documentation/migration/repeatable : 可重复迁移没有版本。相反,每次校验和更改时,都会(重新)应用它们。 这对于管理数据库对象非常有用,这些对象的定义可以简单地在版本控制中的单个文件中维护。 在一次迁移运行中,可重复迁移始终在所有挂起的版本化迁移执行完毕后最后应用。可重复迁移按其描述的顺序应用。 这听起来

  • 我想将我的项目迁移到空安全,但是dependecie不支持空安全:

  • 问题内容: 我刚刚开始使用MongoDb,我注意到我有很多重复的记录,这些记录本来就是唯一的。我想知道如何对数据使用组合键,并且正在寻找有关如何创建它们的信息。最后,我使用Java来访问mongo和morphia作为我的ORM层,因此将您的答案中的内容包括在内是非常棒的。 Morphia:http : //code.google.com/p/morphia/ 问题答案: 您也可以将对象用于_id字