sql >> Database >  >> NoSQL >> MongoDB

Aggregatiepijplijnstadia voorwaardelijk opnemen

Wat u wilt doen, is de hele pijplijn bouwen, afhankelijk van de geboden opties. Het is tenslotte maar een datastructuur.

U test ook onjuist voor een "array" en u zou instanceof omdat typeof zou eigenlijk "object" teruggeven en niet "array" .

Bovendien wil je die voorwaarde echt in de eerste pijplijnfase om de documenten ook optimaal te selecteren, naast dat ze worden toegevoegd na $unwind waar nodig:

var pipeline = [
  { $match: 
      Object.assign(
        { 'shop.nameSlug' : req.query.nameSlug },
        (req.query.status) 
          ? { "status.status": (req.query.status instanceof Array)
            ? { "$in": req.query.status } : req.query.status }
          : {}
      )
  },
  { $unwind: "$status" },
  ...(
    (req.query.status)
      ? [{ "$match": { 
          "status.status": (req.query.status instanceof Array)
           ? { "$in": req.query.status } : req.query.status
       }}]
      : []
    ),
    { $group: {
      _id: "$_id",
      status: { $addToSet: "$status" },
      number: { $first: "$number" },
      date: { $first: "$date" },
      comment: { $first: "$comment" }
    }}
];    


Order.aggregate(pipeline).exec(function(err, orders){

})

Gegeven een req object met iets aanwezig in status je krijgt:

// Example stucture
var req = {
  query: { 
   nameSlug: "Bill", 
   status: "A"
  },
};

// Pipeline output as:

[
    {
        "$match" : {
            "shop.nameSlug" : "Bill",
            "status.status" : "A"
        }
    },
    {
        "$unwind" : "$status"
    },
    {
        "$match" : {
            "status.status" : "A"
        }
    },
    {
        "$group" : {
            "_id" : "$_id",
            "status" : {
                "$addToSet" : "$status"
            },
            "number" : {
                "$first" : "$number"
            },
            "date" : {
                "$first" : "$date"
            },
            "comment" : {
                "$first" : "$comment"
            }
        }
    }
]

Met een array:

var req = {
  query: { 
   nameSlug: "Bill", 
   status: ["A","B"]
  },
};

// Pipeline output as:
[
    {
        "$match" : {
            "shop.nameSlug" : "Bill",
            "status.status" : {
                "$in" : [ 
                    "A", 
                    "B"
                ]
            }
        }
    },
    {
        "$unwind" : "$status"
    },
    {
        "$match" : {
            "status.status" : {
                "$in" : [ 
                    "A", 
                    "B"
                ]
            }
        }
    },
    {
        "$group" : {
            "_id" : "$_id",
            "status" : {
                "$addToSet" : "$status"
            },
            "number" : {
                "$first" : "$number"
            },
            "date" : {
                "$first" : "$date"
            },
            "comment" : {
                "$first" : "$comment"
            }
        }
    }
]

En met niets:

var req = {
  query: { 
   nameSlug: "Bill", 
   //status: ["A","B"]
  },
};

// Pipeline output as:
[
    {
        "$match" : {
            "shop.nameSlug" : "Bill"
        }
    },
    {
        "$unwind" : "$status"
    },
    {
        "$group" : {
            "_id" : "$_id",
            "status" : {
                "$addToSet" : "$status"
            },
            "number" : {
                "$first" : "$number"
            },
            "date" : {
                "$first" : "$date"
            },
            "comment" : {
                "$first" : "$comment"
            }
        }
    }
]

U kunt dus zien waar de onderdelen voorwaardelijk zijn opgenomen, afhankelijk van de opgegeven waarden.

$filter gebruiken

Je zou echt $filter moeten gebruiken hier in plaats daarvan. Het is een stuk efficiënter dan $unwind en je bent echt niets aan het groeperen. Het enige dat u echt wilt, zijn gefilterde arrays. Dus dat is alles wat je voorwaardelijk toevoegt:

var pipeline = [
  { $match: 
      Object.assign(
        { 'shop.nameSlug' : req.query.nameSlug },
        (req.query.status) 
          ? { "status.status": (req.query.status instanceof Array)
            ? { "$in": req.query.status } : req.query.status }
          : {}
      )
  },
  ...(
    (req.query.status)
      ? [{ "$addFields": { 
          "status": {
            "$filter": {
              "input": "$status",
              "cond": {
                [(req.query.status instanceof Array) ? "$in" : "$eq"]:
                  [ "$$this.status", req.query.status ]
              }
            }    
          }
       }}]
      : []
    )
];

De keuze is tussen $in en $eq voor de vergelijkingstest, afhankelijk van het geleverde. Je kunt optioneel het hele ding in $setUnion als u "echt van plan bent" een "set" in het resultaat te gebruiken. Maar het ziet er over het algemeen uit alsof je gewoon waarden uit de array wilt "filteren".

Met dezelfde verwachtingen van een enkele waarde:

var req = {
  query: { 
   nameSlug: "Bill", 
   //status: ["A","B"]
   status: "A"
  },
};

/* 1 */
[
    {
        "$match" : {
            "shop.nameSlug" : "Bill",
            "status.status" : "A"
        }
    },
    {
        "$addFields" : {
            "status" : {
                "$filter" : {
                    "input" : "$status",
                    "cond" : {
                        "$eq" : [ 
                            "$$this.status", 
                            "A"
                        ]
                    }
                }
            }
        }
    }
]

Een array:

var req = {
  query: { 
   nameSlug: "Bill", 
   status: ["A","B"]
  },
};

/* 1 */
[
    {
        "$match" : {
            "shop.nameSlug" : "Bill",
            "status.status" : {
                "$in" : [ 
                    "A", 
                    "B"
                ]
            }
        }
    },
    {
        "$addFields" : {
            "status" : {
                "$filter" : {
                    "input" : "$status",
                    "cond" : {
                        "$in" : [ 
                            "$$this.status", 
                            [ 
                                "A", 
                                "B"
                            ]
                        ]
                    }
                }
            }
        }
    }
]

Of niets:

var req = {
  query: { 
   nameSlug: "Bill", 
   //status: ["A","B"]
  },
};

/* 1 */
[
    {
        "$match" : {
            "shop.nameSlug" : "Bill"
        }
    }
]

Als u niet hoeft te filteren, laat u gewoon de extra pijplijnfase vallen.




  1. MongoDB-replicaset:verschil in schijfgrootte in primaire en secundaire knooppunten

  2. spring-boot redis :Hoe alle sessies van een gebruiker ongeldig maken?

  3. mangoest Datum vergelijken zonder tijd en groeperen op meerdere eigenschappen?

  4. Hoe de waarde van een specifiek ingesloten document, in een array, van een specifiek document in MongoDB bij te werken?