从 MongoDB 中的手册参考中查找所有嵌入文档
Find all embedded documents from manual reference in MongoDB
我在项目中使用MongoDB和Spring引导。我用manual reference点了一个集合,我的结构如下:
卷轴合集
{
_id : "reel_id_1",
name: "reel 1",
category :[
{
_id : "category_id_1",
name: "category 1",
videos: ["video_id_1","video_id_2"]
}
]
}
视频合集
{
_id: "video_id_1", // first document
name: "mongo"
}
{
_id: "video_id_2", // seconddocument
name: "java"
}
Java类是
@Document
@Data
public class Reel {
@Id
private ObjectId _id;
private String name;
List<Category> category;
}
@Data
public class Category {
@Id
private ObjectId _id=new ObjectId();
private String name;
Video videos;
}
@Document
@Data
public class Video {
@Id
private ObjectId _id = new ObjectId();
private String name;
}
我尝试通过 mongoTemplate 加入两个文档
public List<Reel> findById(ObjectId _id) {
LookupOperation lookupOperation = LookupOperation.newLookup()
.from("video")
.localField("category.videos")
.foreignField("_id")
.as("category.videos");
UnwindOperation unwindOperation = Aggregation.unwind("category");
Aggregation agg = newAggregation(unwindOperation,match(Criteria.where("_id").is(_id)),lookupOperation);
Aggregation aggregation = newAggregation(lookupOperation);
List<Reel> results = mongoTemplate.aggregate(aggregation, "reel", Reel.class).getMappedResults();
return results;
}
但是它抛出一个错误。
Failed to instantiate java.util.List using constructor NO_CONSTRUCTOR with arguments
但是因为我使用了“unwind”,所以我创建了一个新实体 UnwindReel 并添加了 Category category
而不是 List<Category> category
。并使用
List<UnwindReel> results = mongoTemplate.aggregate(aggregation, "reel", UnwindReel.class).getMappedResults();
它仅结合第一个视频 (video_id_1) 对象。如何获取 videos 数组 中的所有对象?有什么方法可以获取吗?
您存储在数据库中的 JSON 结构错误。您的 Reel
class 需要 Category
列表,但在数据库中您已存储为嵌套 object.
您需要在 $lookup
之后添加此阶段
{
"$addFields": {
"category": {
"$map": {
"input": "$category.videos",
"in": {
"videos": "$$this"
}
}
}
}
}
Java代码
public List<Reel> findById(String _id) {
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(Criteria.where("_id").is(_id)),
Aggregation.lookup(mongoTemplate.getCollectionName(Video.class), "category.videos", "_id", "category.videos"),
new AggregationOperation() {
@Override
public Document toDocument(AggregationOperationContext context) {
return new Document("$addFields",
new Document("category", new Document("$map", new Document("input", "$category.videos")
.append("in", new Document("videos", "$$this")))));
}
})
.withOptions(AggregationOptions.builder().allowDiskUse(Boolean.TRUE).build());
LOG.debug(
aggregation.toString().replaceAll("__collection__", mongoTemplate.getCollectionName(Reel.class)));
return mongoTemplate.aggregate(aggregation, mongoTemplate.getCollectionName(Reel.class), Reel.class)
.getMappedResults();
}
建议
- 不要hard-codecollection名字,使用更好的
mongoTemplate.getCollectionName
方法
- 执行前始终记录聚合管道,这有助于调试。
- 如果您的 collection 将来会增长,请使用
{allowDiskUse: true}
MongoDb 聚合选项。
我在项目中使用MongoDB和Spring引导。我用manual reference点了一个集合,我的结构如下:
卷轴合集
{
_id : "reel_id_1",
name: "reel 1",
category :[
{
_id : "category_id_1",
name: "category 1",
videos: ["video_id_1","video_id_2"]
}
]
}
视频合集
{
_id: "video_id_1", // first document
name: "mongo"
}
{
_id: "video_id_2", // seconddocument
name: "java"
}
Java类是
@Document
@Data
public class Reel {
@Id
private ObjectId _id;
private String name;
List<Category> category;
}
@Data
public class Category {
@Id
private ObjectId _id=new ObjectId();
private String name;
Video videos;
}
@Document
@Data
public class Video {
@Id
private ObjectId _id = new ObjectId();
private String name;
}
我尝试通过 mongoTemplate 加入两个文档
public List<Reel> findById(ObjectId _id) {
LookupOperation lookupOperation = LookupOperation.newLookup()
.from("video")
.localField("category.videos")
.foreignField("_id")
.as("category.videos");
UnwindOperation unwindOperation = Aggregation.unwind("category");
Aggregation agg = newAggregation(unwindOperation,match(Criteria.where("_id").is(_id)),lookupOperation);
Aggregation aggregation = newAggregation(lookupOperation);
List<Reel> results = mongoTemplate.aggregate(aggregation, "reel", Reel.class).getMappedResults();
return results;
}
但是它抛出一个错误。
Failed to instantiate java.util.List using constructor NO_CONSTRUCTOR with arguments
但是因为我使用了“unwind”,所以我创建了一个新实体 UnwindReel 并添加了 Category category
而不是 List<Category> category
。并使用
List<UnwindReel> results = mongoTemplate.aggregate(aggregation, "reel", UnwindReel.class).getMappedResults();
它仅结合第一个视频 (video_id_1) 对象。如何获取 videos 数组 中的所有对象?有什么方法可以获取吗?
您存储在数据库中的 JSON 结构错误。您的 Reel
class 需要 Category
列表,但在数据库中您已存储为嵌套 object.
您需要在 $lookup
{
"$addFields": {
"category": {
"$map": {
"input": "$category.videos",
"in": {
"videos": "$$this"
}
}
}
}
}
Java代码
public List<Reel> findById(String _id) {
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(Criteria.where("_id").is(_id)),
Aggregation.lookup(mongoTemplate.getCollectionName(Video.class), "category.videos", "_id", "category.videos"),
new AggregationOperation() {
@Override
public Document toDocument(AggregationOperationContext context) {
return new Document("$addFields",
new Document("category", new Document("$map", new Document("input", "$category.videos")
.append("in", new Document("videos", "$$this")))));
}
})
.withOptions(AggregationOptions.builder().allowDiskUse(Boolean.TRUE).build());
LOG.debug(
aggregation.toString().replaceAll("__collection__", mongoTemplate.getCollectionName(Reel.class)));
return mongoTemplate.aggregate(aggregation, mongoTemplate.getCollectionName(Reel.class), Reel.class)
.getMappedResults();
}
建议
- 不要hard-codecollection名字,使用更好的
mongoTemplate.getCollectionName
方法 - 执行前始终记录聚合管道,这有助于调试。
- 如果您的 collection 将来会增长,请使用
{allowDiskUse: true}
MongoDb 聚合选项。