MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Percentuale di condizioni OR corrispondenti in mongodb

Bene, la tua soluzione dovrebbe davvero essere specifica per MongoDB, altrimenti finirai per eseguire i tuoi calcoli e possibili corrispondenze sul lato client, e questo non sarà positivo per le prestazioni.

Quindi, ovviamente, quello che vuoi davvero è un modo per avere quell'elaborazione sul lato server:

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 } }

])

Quindi, come sai, la "lunghezza" del $or condizione applicata, devi semplicemente scoprire quanti elementi nell'array "caratteristiche" corrispondono a tali condizioni. Ecco di cosa tratta la seconda $match nella pipeline.

Una volta ottenuto quel conteggio, dividi semplicemente per il numero di condizioni che sono state trasmesse come $or . Il bello qui è che ora puoi fare qualcosa di utile con questo come ordinare in base a quella pertinenza e quindi persino "paginare" il lato server dei risultati.

Ovviamente, se vuoi una "categorizzazione" aggiuntiva di questo, tutto ciò che devi fare è aggiungere un altro $project fase fino alla fine del gasdotto:

    { "$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"
                ]} 
            ]}
        ]}
    }}

O come qualcosa di simile. Ma il $cond l'operatore può aiutarti qui.

L'architettura dovrebbe andare bene così come ce l'hai in quanto puoi avere un indice composto sulla "chiave" e sul "valore" per le voci nell'array delle funzionalità e questo dovrebbe ridimensionarsi bene per le query.

Ovviamente se hai effettivamente bisogno di qualcosa di più, come la ricerca sfaccettata e i risultati, puoi guardare soluzioni come Solr o ricerca elastica. Ma l'implementazione completa di ciò sarebbe un po' lunga per qui.