我需要从springboot应用程序中使用mongoDb findAndModify。但是,在更新时,将删除表中的_class列。如果没有此列,springboot将无法对数据进行编组。
在客户端我使用带有org.springframework.data:spring-data-mongodb:1.10.6.RELEASE
我的mongoDb服务器版本= 3.4.7
这是以前的行:
> coll.find( {"_id":"job-20"} )
{ "_id" : "job-20",
"_class" : "org.alleninstitute.aics.statustracker.JobStatus",
"steps" : [{
"step" : "busted",
"stepStatus" : {
"_class" : "org.alleninstitute.aics.statustracker.states.Blocked",
"by" : [ "jag", "zig" ]
}
},
{ "step" : "zig",
"stepStatus" : {
"_class" : "org.alleninstitute.aics.statustracker.states.Working",
"host" : "GPU-X001",
"message" : "the landing is secured"
}
},
{ "step" : "jag",
"stepStatus" : {
"_class" : "org.alleninstitute.aics.statustracker.states.Succeeded",
"host" : "GEO-01"
}
} ],
"version" : 2 }
这是以后的行:
{
"_id": "job-20",
"_class": "org.alleninstitute.aics.statustracker.JobStatus",
"steps": [{
"step": "busted",
"stepStatus": {
"host": "galangal",
"message": "used in thai food"
}
}, {
"step": "zig",
"stepStatus": {
"host": "GPU-X001",
"message": "the landing is secured"
}
}, {
"step": "jag",
"stepStatus": {
"host": "GEO-01"
}
}],
"version": 3
}
使用MongoOperations.save
保留_class。但我需要使用MongoOperations.findAndModify
来实现其并发更新功能。
我想知道是否会有一个简单的解决方法。
这是用于原子更新的代码:
private JobStatus updateStep(JobStatus jobStatus, String step, StepStatus stepStatus) {//updates the passed jobStatus and returns the updated object}
@PostMapping("/status/update")
public JobStatus update(@RequestBody StepAndStepStatus stepAndStepStatus) {
String jobId = "job-20";
String step = stepAndStepStatus.step;
StepStatus stepStatus = stepAndStepStatus.stepStatus;
while (true) {
JobStatus oldJobStatus = repo.findByJobId(jobId);
if (oldJobStatus == null)
throw new IllegalArgumentException(String.format("no job with jobId: %s", jobId));
JobStatus updatedJobStatus = updateStep(oldJobStatus, step, stepStatus);
Query query = new Query();
query.addCriteria(Criteria.where("version").is(oldJobStatus.version));
query.addCriteria(Criteria.where("_id").is(jobId));
Update update = new Update();
update.set("steps", updatedJobStatus.steps);
update.set("version", oldJobStatus.version + 1);
JobStatus os = mongoOperation.findAndModify(query, update, JobStatus.class);
if (os != null)
return updatedJobStatus;
}
}
POJO:
public class JobStatus {
@Id
public String jobId;
@JsonSubTypes.Type(value = LinkedList.class)
public List<StepAndStepStatus> steps;
public int version;
public JobStatus() {}
public JobStatus(String jobId, List<StepAndStepStatus> steps, int version) {
this.jobId = jobId;
this.steps = steps;
this.version = version;
}
@Override
public String toString() {
return String.format("Job[id=%s, steps=%s, version=%d]", jobId, steps.toString(), version);
}
}
public class StepAndStepStatus {
public String step;
public StepStatus stepStatus;
public StepAndStepStatus(String step, StepStatus stepStatus) {
this.step = step;
this.stepStatus = stepStatus;
}
public StepAndStepStatus() {}
public String toString() {
return String.format("step: %s stepStatus: %s", step, stepStatus);
}
}
public class Blocked extends StepStatus {
// The set of steps that block this step
public Set<String> by;
public Blocked() {this(Collections.<String>emptySet());}
public Blocked(Set<String> by) {
super();
this.by = by;
}
public boolean active() {return true;}
public boolean failed() {return false;}
public String toString() {
return String.format("by: %s ", by);
}
}
public class Working extends StepStatus {
public String host;
public String message;
public Working(String host, String message) {
super();
this.host = host;
this.message = message;
}
public Working() {this("", "");}
public String toString() {
return String.format("host: %s message: %s", host, message);
}
public boolean active() {return true;}
public boolean failed() {return false;}
}
public class Succeeded extends StepStatus {
public String host;
public Succeeded(String host) {
super();
this.host = host;
}
public boolean active() {return false;}
public boolean failed() {return false;}
public Succeeded() {this("");}
public String toString() {
return String.format("host: %s", host);
}
}
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@Type(value = Waiting.class, name = "waiting"),
@Type(value = Working.class, name = "working"),
@Type(value = Retrying.class, name = "retrying"),
@Type(value = Blocked.class, name = "blocked"),
@Type(value = Succeeded.class, name = "succeeded"),
@Type(value = Failed.class, name = "failed")
})
public abstract class StepStatus {
public abstract boolean active();
public abstract boolean failed();
}