首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >带有Java异步驱动程序的MongoDB:$lookup始终为空

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

Stack Overflow用户
提问于 2017-11-28 13:26:39
回答 1查看 703关注 0票数 1

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

代码语言:javascript
运行
复制
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;
    ...
}

其想法是只在购买和加载(或:联接)适当的用户文档时使用UserId聚合函数来保留$lookup。因为Purchase.user属性永远不应该保存在MongoDB中,所以它被声明为瞬态属性。这个能行吗?

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

代码语言:javascript
运行
复制
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在结果中始终是空的。我还尝试使用手动投影来解释用户:

代码语言:javascript
运行
复制
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解码时发生异常。解码为“购买”失败,但有以下例外: 无法解码“用户”。readStartDocument只能在CurrentBSONType是文档时调用,而不能在CurrentBSONType是数组时调用。 自定义代码或PojoCodec可能需要显式配置和注册以处理此类型。

我遗漏了什么?

EN

Stack Overflow用户

发布于 2017-11-29 10:29:04

明白了。

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

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

另一个问题是,transient属性既没有序列化也没有反序列化。解决方法是将getter标记为@BsonIgnore,而不是setter。这样,在序列化时跳过属性,而在反序列化时跳过属性。

代码语言:javascript
运行
复制
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来提取第一个条目,如下所示:

代码语言:javascript
运行
复制
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);
票数 1
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47532741

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档