最近在使用spring data mongodb做开发中,遇到一个比较烦心的事,像下面这样的mongodb原生操作,不知道如何用代码实现:
# 计算今年某用户发放工资总额,并保留每月发放的工资详情
db.user.update(
{
"_id": ObjectId("5583ea45e4b04cd50ed873a5")
},
{
"$inc": {
"salarys": 4000
},
"$push": {
"salarys.items.daily": {
"$each": [
{
"salary" : 3300,
"grantDate" : ISODate("2015-07-10T00:00:00.000Z")
},
{
"salary" : 4000,
"grantDate" : ISODate("2015-08-10T00:00:00.000Z")
}
],
"$slice": -12,
"$sort": {"grantDate": -1}
}
}
}
)
查看了Spring Data MongoDB的官方API依旧没有收获,我发现core.query.Update.push(String key)操作并没有$slice
链操作,仅仅支持$each
操作,于是我又查看了MongoDB Java Driver的官方API,发现其com.mongodb.bulk.UpdateRequest请求是直接针对 BsonDocument的操作。算了,还是看看Spring Data MongoDB关于Update的实现吧,这一看发现了端倪,其实我们可以直接利用[M
]addMultiFieldOperation - keyValueMap.put(key, value);
将要更新的文档直接像它那样包装成DBObject,直接push就OK了。
// Spring Data MongoDB中Update类的核心方法
protected void addMultiFieldOperation(String operator,
String key, Object value) {
Assert.hasText(key, "Key/Path for update must not be null
or blank.");
Object existingValue = this.modifierOps.get(operator);
DBObject keyValueMap;
if (existingValue == null) {
keyValueMap = new BasicDBObject();
this.modifierOps.put(operator, keyValueMap);
} else {
if (existingValue instanceof BasicDBObject) {
keyValueMap = (BasicDBObject) existingValue;
} else {
throw new InvalidDataAccessApiUsageException("Modifier
Operations should be a LinkedHashMap but was " +
existingValue.getClass());
}
}
keyValueMap.put(key, value);
this.keysToUpdate.add(key);
}
下面是我对示例的java实现(部分):
注意:MongoDB要求不能只将$slice
或者$sort
与$push
配合使用,且必须使用$each
。而$each
操作要求是JSON Array,接下来你懂得!
List<Map> dailyMaps = new ArrayList<Map>();
Map dailyMap = new HashMap();
dailyMap.put("salary", salary);
dailyMap.put("grantDate", date);
dailyMaps.add(dailyMaps);
BasicDBObject dbObject = new BasicDBObject();
dbObject.put("$each", dailyMaps);
dbObject.put("$slice", -12);
dbObject.put("$sort", new BasicBSONObject("grantDate", 1));
update.push("salarys.items.daily", dbObject);
小贴士:
关于对MongoDB中字段的过滤实现:
MongoDB Java Driver中使用coll.find().projection(fields(include("x", "y"), excludeId()));
Spring Data MongoDB中使用query.fields().exclude("salarys");
详情见参考链接。参考链接: Projections & Spring Data MongoDB API