2017-04-01 3 views
0

Ich habe folgende zwei Dokumentschemas.Wie Dokumente zu aggregieren und dann einige von ihnen herauszufiltern?

TradeRequests

TradeRequestSchema = mongoose.Schema({ 
    status: { 
    type: String, 
    enum: ["opened", "closed", "rejected", "accepted"], 
    default: "opened" 
    }, 

    _requester: { 
    required: true, 
    type: mongoose.Schema.Types.ObjectId, 
    ref: 'User' 
    }, 

    _requestedBook: { 
    required: true, 
    type: mongoose.Schema.Types.ObjectId, 
    ref: 'Book' 
    }, 

    _exchangeBook: { 
    type: mongoose.Schema.Types.ObjectId, 
    ref: 'Book' 
    } 
}); 

Books

BookSchema = mongoose.Schema({ 
    title: { 
    type: String, 
    trim: true, 
    minlength: 1, 
    required: true 
    }, 

    description: { 
    type: String, 
    trim: true, 
    minlength: 5 
    }, 

    thumbnailURL: { 
    type: String, 
    trim: true, 
    minlength: 1, 
    validate: { 
     validator: url => validator.isURL(url), 
     message: '{VALUE} is not a valid URL' 
    }, 
    required: true 
    }, 

    _ownedBy: { 
    type: mongoose.Schema.Types.ObjectId, 
    ref: 'User', 
    required: true 
    }, 

    _addedBy: { 
    type: mongoose.Schema.Types.ObjectId, 
    ref: 'User', 
    required: true 
    } 
}); 

Wie aus ersichtlich sein, über jedes Buch einen Eigentümer hat.

Sie können sehen, dass die tradeRequests-Sammlung die '_id' des Benutzers, auf den sie abzielt, nicht direkt speichert.

Es wird indirekt gespeichert, indem '_id' des angeforderten Buchs gespeichert wird, von dem '_ownedBy' Wert abgerufen werden kann.

Ich versuche, alle TradeRequests abzurufen, die auf einen bestimmten Benutzer abzielen (nicht initiiert von).

Um dies zu erreichen, habe ich diese Abfrage verwendet. Ich kam mit ihm nach oben, nachdem bei dieser Antwort suchen - Aggregation filter after $lookup

db.traderequests.aggregate([{ 
    $lookup: { 
     from: "books", 
     localField: "_requestedBook", 
     foreignField: "_id", 
     as: "books" 
    } 
}, { 
    $project: { 
     _requester: 1, 
     books: { 
      $filter: { 
       input: "$books", 
       as: "book", 
       cond: { 
        $eq: ["$$book._ownedBy", ObjectId("a particular id")] 
       } 
      } 
     } 
    } 
}]) 

Problem ist es eine Sammlung von Dokumenten, so etwas wie dieses gibt -

{ 
    "_id": ObjectId("58db9303f431063cb5de2dd1"), 
    "_requester": ObjectId("58db9303f431063cb5de2dc5"), 
    "books": [] 
} { 
    "_id": ObjectId("58db9303f431063cb5de2dd2"), 
    "_requester": ObjectId("58db9303f431063cb5de2dc8"), 
    "books": [{ 
     "_id": ObjectId("58db9303f431063cb5de2dc9"), 
     "__v": 0, 
     "title": "Harry Potter", 
     "description": "Harry book & the cursed child.", 
     "thumbnailURL": "https://books.google.co.in/books/content?id=tcSMCwAAQBAJ&printsec=frontcover&img=1&zoom=1&imgtk=AFLRE73GrnaBHte0hGE_NwNwDUzVXAlh_v8I8YFYLVz8drUTind520RmD7wuWg9dp6cYFFaxcDIQZyRors6X1YGBVq9ycDUIFGWJt-izl8bjpEw4BdOjWmvO3brt9I3NpM3NMXzgu_Xl", 
     "_ownedBy": ObjectId("58db9303f431063cb5de2dc5"), 
     "_addedBy": ObjectId("58db9303f431063cb5de2dc5") 
    }] 
} { 
    "_id": ObjectId("58db9303f431063cb5de2dd3"), 
    "_requester": ObjectId("58db9303f431063cb5de2dc6"), 
    "books": [] 
} 

Wie Sie es noch holt alle sehen Unterlagen. Es ist nur, dass es das Array für Dokumente ausfiltert und leert, die nicht der Filterbedingung entsprechen.

würde ich es vorziehen, ein Ergebnis wie dieses zu erhalten -

{ 
    "_id": ObjectId("58db9303f431063cb5de2dd2"), 
    "_requester": ObjectId("58db9303f431063cb5de2dc8"), 
    "books": [{ 
     "_id": ObjectId("58db9303f431063cb5de2dc9"), 
     "__v": 0, 
     "title": "Harry Potter", 
     "description": "Harry book & the cursed child.", 
     "thumbnailURL": "https://books.google.co.in/books/content?id=tcSMCwAAQBAJ&printsec=frontcover&img=1&zoom=1&imgtk=AFLRE73GrnaBHte0hGE_NwNwDUzVXAlh_v8I8YFYLVz8drUTind520RmD7wuWg9dp6cYFFaxcDIQZyRors6X1YGBVq9ycDUIFGWJt-izl8bjpEw4BdOjWmvO3brt9I3NpM3NMXzgu_Xl", 
     "_ownedBy": ObjectId("58db9303f431063cb5de2dc5"), 
     "_addedBy": ObjectId("58db9303f431063cb5de2dc5") 
    }] 
} 

Hier werden nur die Dokumente zurückgegeben werden, deren Bücher Array ist nicht leer.

In Mysql wäre dies sehr einfach.

select * from traderequests left join books on traderequests.requestedbook = books.id where books.ownerId = 'a particular id'; 

Wie erreiche ich das? Gibt es etwas, das ich nicht verstehe über Mongodb-Aggregation?

Bitte helfen.

Antwort

0

können Sie $unwind + $match nach lookup hinzufügen, die als ob die Anwendung $lookup mit Match-Filter arbeiten optimiert ist.

{$unwind:"$books"}, 
{$match:{"books._ownedBy": ObjectId("a particular id")}}, 
{$group:{"_id":"$_id", "_requester":{$first:"$_requester"}, "books":{$push:"$books"}}} 

Oder

Sie können $match Bühne am Ende hinzufügen.

So etwas wie {$match:{"books":{$ne:[]}}}

+0

ich diese Redact Abfrage verwendet '' 'db.traderequests.Aggregat ([{ $ Lookup: { aus: "Bücher", localField: "_requestedBook", foreignField: "_id", als: "Bücher" } }, { $ Redact: { $ Cond : [{ $ eq: [{$ ifNull: ["$ _ownedBy", ObjectId ("einige id")]}, ObjectId ("einige id")] }, "$$ DESCEND", "$$ PRUNE " ] } } ])' ''. Habe das gleiche Ergebnis. –

+0

Die zweite Option konnte nicht funktionieren. Die dritte Option funktioniert. Aber ich möchte wissen, warum die Spielbedingung überhaupt erforderlich ist? Aufgrund leerer Array-Dokumente sollte der Filter korrekt gelöscht worden sein, wie in der anderen Frage, die ich verlinkt habe, dargestellt wurde. –

+0

Ich habe die erste Option entfernt, da sie in Ihrem Fall nicht anwendbar ist. Fixierte zweite Option. '$ filter' wird nur zum Filtern von Array-Elementen verwendet, dh leer, wenn kein Element gefunden wird. Das einschließende Dokument wird nicht gefiltert. – Veeram

Verwandte Themen