MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Prozentsatz der OR-Bedingungen, die in Mongodb übereinstimmen

Nun, Ihre Lösung sollte wirklich MongoDB-spezifisch sein, sonst werden Sie Ihre Berechnungen und möglichen Abgleiche auf der Client-Seite durchführen, und das wird der Leistung nicht gut tun.

Was Sie also wirklich wollen, ist eine Möglichkeit, diese Verarbeitung auf der Serverseite zu haben:

db.products.aggregate([

    // Match the documents that meet your conditions
    { "$match": {
        "$or": [
            { 
                "features": { 
                    "$elemMatch": {
                       "key": "Screen Format",
                       "value": "16:9"
                    }
                }
            },
            { 
                "features": { 
                    "$elemMatch": {
                       "key" : "Weight in kg",
                       "value" : { "$gt": "5", "$lt": "8" }
                    }
                }
            },
        ]
    }},

    // Keep the document and a copy of the features array
    { "$project": {
        "_id": {
            "_id": "$_id",
            "product_id": "$product_id",
            "ean": "$ean",
            "brand": "$brand",
            "model": "$model",
            "features": "$features"
        },
        "features": 1
    }},

    // Unwind the array
    { "$unwind": "$features" },

    // Find the actual elements that match the conditions
    { "$match": {
        "$or": [
            { 
               "features.key": "Screen Format",
               "features.value": "16:9"
            },
            { 
               "features.key" : "Weight in kg",
               "features.value" : { "$gt": "5", "$lt": "8" }
            },
        ]
    }},

    // Count those matched elements
    { "$group": {
        "_id": "$_id",
        "count": { "$sum": 1 }
    }},

    // Restore the document and divide the mated elements by the
    // number of elements in the "or" condition
    { "$project": {
        "_id": "$_id._id",
        "product_id": "$_id.product_id",
        "ean": "$_id.ean",
        "brand": "$_id.brand",
        "model": "$_id.model",
        "features": "$_id.features",
        "matched": { "$divide": [ "$count", 2 ] }
    }},

    // Sort by the matched percentage
    { "$sort": { "matched": -1 } }

])

Sie kennen also die "Länge" von $or Bedingung angewendet wird, dann müssen Sie einfach herausfinden, wie viele der Elemente im Array "features" diese Bedingungen erfüllen. Darum geht es beim zweiten $match in der Pipeline.

Sobald Sie diese Zählung haben, dividieren Sie einfach durch die Anzahl der Bedingungen, die als Ihr $or übergeben wurden . Das Schöne daran ist, dass Sie jetzt etwas Nützliches damit machen können, wie zum Beispiel nach Relevanz sortieren und dann sogar die Ergebnisse serverseitig "seitenweise" anzeigen.

Wenn Sie natürlich eine zusätzliche "Kategorisierung" davon wünschen, müssten Sie lediglich ein weiteres $project hinzufügen Stufe bis zum Ende der Pipeline:

    { "$project": {
        "product_id": 1
        "ean": 1
        "brand": 1
        "model": 1,
        "features": 1,
        "matched": 1,
        "category": { "$cond": [
            { "$eq": [ "$matched", 1 ] },
            "100",
            { "$cond": [ 
                { "$gte": [ "$matched", .7 ] },
                "70-99",
                { "$cond": [
                   "$gte": [ "$matched", .4 ] },
                   "40-69",
                   "under 40"
                ]} 
            ]}
        ]}
    }}

Oder als etwas ähnliches. Aber die $cond Betreiber kann Ihnen dabei helfen.

Die Architektur sollte so gut sein, wie Sie sie haben, da Sie einen zusammengesetzten Index für "Schlüssel" und "Wert" für die Einträge in Ihrem Features-Array haben können, und dies sollte für Abfragen gut skaliert werden.

Wenn Sie tatsächlich etwas mehr als das benötigen, z. B. facettierte Suche und Ergebnisse, können Sie sich natürlich Lösungen wie Solr oder elastische Suche ansehen. Aber die vollständige Implementierung davon würde hier etwas langwierig sein.