2017-11-28 22 views
0

私はこの二つの「リンク」POJOエンティティがあります。適切:アイデアは(JOINまたは)のみの購入や負荷のためのユーザーIDを持続することである

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集約関数を使用してオンデマンドでユーザー文書を表示します。 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。 「購入」へ デコードが次の例外で失敗しました:

は、「ユーザー」をデコードすることができませんでした。 readStartDocumentは、012BSCurrentBSONTypeがDOCUMENTの場合にのみ呼び出され、CurrentBSONTypeがARRAYの場合は呼び出されません。

コーデックやPojoCodecが明示的に設定して このタイプを処理するために登録する必要があるかもしれないカスタム。

私は何が欠けていますか?

答えて

0

は入力 文書に追加する新しい配列フィールドの名前を指定します。

最初の間違いは、フィールドが配列である必要があります「と」ということでした。新しい配列フィールドには、fromコレクションの の一致するドキュメントが含まれています。指定された名前が既に文書 に存在する場合、既存のフィールドは上書きされます。

もう1つの問題は、transientプロパティがシリアル化されず、逆シリアル化されないことです。これを回避するには、getterを@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; 
    } 
} 

あなたは私の場合のように1つのオブジェクトに配列を制限したい場合は、このような最初のエントリを引っ張って、あなたのpipeplineで$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); 
関連する問題