繁体   English   中英

具有Java异步驱动程序的MongoDB:$ lookup始终为空

[英]MongoDB with Java async driver: $lookup always empty

我有以下两个“链接的” POJO实体:

public class User {
    public ObjectId id; // this is mapped to "_id" in the MongoDB
    public String userName;
    ...
}

public class Purchase {
    public ObjectId id; // this is mapped to "_id" in the MongoDB
    public ObjectId userId;
    public transient User user;

    public String productTitle;
    ...
}

想法是仅使用$ lookup聚合函数按需持久保存UserId以进行购买和加载(或:JOIN)相应的User文档。 由于Purchase.user属性不能被保存在MongoDB中,它被声明为瞬态。 能行吗?

现在,在我的PurchaseRepository中,我试图像这样实现它:

public void getSinglePurchaseWithUser(Bson filter, SingleResultCallback<Purchase> callback) {
   Document match = new Document("$match", filter);

   Document lookupFields = new Document("from", "Users");
   lookupFields.put("localField", "userId");
   lookupFields.put("foreignField", "_id");
   lookupFields.put("as", "user");
   Document lookup = new Document("$lookup", lookupFields);

   List<Document> pipeline = Arrays.asList(match, lookup);

   AggregateIterable<Purchase> output = this.collection.aggregate(pipeline);
   output.first(callback);
}

不幸的是,purchase.user在结果中始终为空。 我还尝试手动投影以明确地读取用户:

Document projectFields = new Document("_id", 1);
projectFields.put("userId", 1);
projectFields.put("user", "$user");
...
Document project = new Document("$project", projectFields);

List<Document> pipeline = Arrays.asList(match, lookup, project);

但这会引发错误读取:

org.bson.codecs.configuration.CodecConfigurationException:使用AutomaticPojoCodec解码时发生异常。 解码为“购买”失败,但有以下例外:

无法解码“用户”。 仅在CurrentBSONType为DOCUMENT时才能调用readStartDocument,而在CurrentBSONType为ARRAY时不能调用。

自定义编解码器或PojoCodec可能需要显式配置和注册以处理此类型。

我想念什么?

得到它了。

第一个错误是“ as”字段必须是一个数组:

指定要添加到输入文档中的新数组字段的名称。 新数组字段包含from集合中的匹配文档。 如果输入文档中已经存在指定的名称,则现有字段将被覆盖。

另一个问题是transient属性既不会序列化也不会反序列化。 一种解决方法是将吸气剂标记为@BsonIgnore,而不是setter。 这样,该属性在序列化时被跳过,而在反序列化时不被跳过。

public class Purchase {
    private User user;
    public ObjectId userId;

    @BsonIgnore
    public OrgenicUser getUser() {
        return this.user;
    }

    public void setUser(OrgenicUser value) {
        this.user = value;
    }
}

如果要像我这样将数组限制为一个对象,可以在$getElemAt中使用$getElemAt来拉出第一个条目,如下所示:

Document lookupFields = new Document("from", from);
lookupFields.put("localField", localField);
lookupFields.put("foreignField", foreignField);
lookupFields.put("as", as);
Document lookup = new Document("$lookup", lookupFields);

// pulls the first match from the localField array
Document firstMatch = new Document(as, new Document("$arrayElemAt", Arrays.asList("$" + as, 0)));
// keep all fields and add/update the specified field
Document project = new Document("$addFields", firstMatch);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM