我想添加这个我的解决方案,在某些方面重复之前发布的解决方案。
Mongo 驱动程序 v3.x
对于 Mongo 驱动程序 v3.x,我找到了以下解决方案:
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.util.JSON;
import org.bson.Document;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
public class JsonOperation implements AggregationOperation {
private List<Document> documents;
public JsonOperation(String json) {
Object root = JSON.parse(json);
documents = root instanceof BasicDBObject
? Collections.singletonList(new Document(((BasicDBObject) root).toMap()))
: ((BasicDBList) root).stream().map(item -> new Document((Map<String, Object>) ((BasicDBObject) item).toMap())).collect(Collectors.toList());
}
@Override
public Document toDocument(AggregationOperationContext context) {
// Not necessary to return anything as we override toPipelineStages():
return null;
}
@Override
public List<Document> toPipelineStages(AggregationOperationContext context) {
return documents;
}
}
然后假设在某些资源aggregations.json 中给出了聚合步骤:
[
{
$match: {
"userId": "..."
}
},
{
$lookup: {
let: {
...
},
from: "another_collection",
pipeline: [
...
],
as: "things"
}
},
{
$sort: {
"date": 1
}
}
]
可以按如下方式使用上述类:
import static org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation;
Collection<ResultDao> results = mongoTemplate.aggregate(newAggregation(new JsonOperation(resourceToString("aggregations.json", StandardCharsets.UTF_8))), "some_collection", ResultDao.class).getMappedResults();
Mongo 驱动程序 v4.x
由于 JSON 类已从 Mongo v4 中删除,我已将该类重写如下:
import java.util.Collections;
import java.util.List;
import org.bson.Document;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
public class JsonOperation implements AggregationOperation {
private List<Document> documents;
private static final String DUMMY_KEY = "dummy";
public JsonOperation(String json) {
documents = parseJson(json);
}
static final List<Document> parseJson(String json) {
return (json.startsWith("["))
? Document.parse("{\"" + DUMMY_KEY + "\": " + json + "}").getList(DUMMY_KEY, Document.class)
: Collections.singletonList(Document.parse(json));
}
@Override
public Document toDocument(AggregationOperationContext context) {
// Not necessary to return anything as we override toPipelineStages():
return null;
}
@Override
public List<Document> toPipelineStages(AggregationOperationContext context) {
return documents;
}
@Override
public String getOperator() {
return documents.iterator().next().keySet().iterator().next();
}
}
但是由于字符串操作,实现现在有点难看。如果有人对如何以更优雅的方式解析对象数组有更好的了解,请编辑这篇文章或发表评论。理想情况下,Mongo 核心中应该有一些方法可以解析 JSON 对象或列表(返回 BasicDBObject/BasicDBList 或 Document/List<Document>)。
另外请注意,我已经跳过了在 toPipelineStages() 方法中转换 Document 实例的步骤,因为在我的情况下没有必要:
@Override
public List<Document> toPipelineStages(AggregationOperationContext context) {
return documents.stream().map(document -> context.getMappedObject(document)).collect(Collectors.toList());
}