簡體   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