2 votes

agrégat mongo basé sur des conditions pour filtrer le document pour le versionnement

Je travaille sur la gestion des versions, nous avons des documents basés sur UUIDs et jobUuids et jobUuids sont les documents associés à l'utilisateur qui travaille actuellement. J'ai quelques requêtes agrégées sur ces collections que je dois mettre à jour sur la base des UUIDs de travail,

Les résultats récupérés par la requête agrégée doivent être tels que,

  • si les utilisateurs actuels jobUuid n'existe pas, le document de base avec jobUuid: "default" sera retourné (le document sans jobUuid),
  • si l'uuid du travail existe, seul le document est renvoyé.

J'ai un $match utilisé pour obtenir ces documents sur la base de certaines conditions, à partir de ces documents, je dois filtrer les documents sur la base des conditions ci-dessus, et un exemple est montré ci-dessous,

Les données ressemblent à ceci :

[
  {
    "uuid": "5cdb5a10-4f9b-4886-98c1-31d9889dd943",
    "name": "adam",
    "jobUuid": "default",
  },
  {
    "uuid": "5cdb5a10-4f9b-4886-98c1-31d9889dd943",
    "jobUuid": "d275781f-ed7f-4ce4-8f7e-a82e0e9c8f12",
    "name": "adam"
  },
  {
    "uuid": "b745baff-312b-4d53-9438-ae28358539dc",
    "name": "eve",
    "jobUuid": "default",
  },
  {
    "uuid": "b745baff-312b-4d53-9438-ae28358539dc",
    "jobUuid": "d275781f-ed7f-4ce4-8f7e-a82e0e9c8f12",
    "name": "eve"
  },
  {
    "uuid": "26cba689-7eb6-4a9e-a04e-24ede0309e50",
    "name": "john",
    "jobUuid": "default",
  }
]

Résultats pour "jobUuid": "d275781f-ed7f-4ce4-8f7e-a82e0e9c8f12" devrait être :

[
  {
    "uuid": "5cdb5a10-4f9b-4886-98c1-31d9889dd943",
    "jobUuid": "d275781f-ed7f-4ce4-8f7e-a82e0e9c8f12",
    "name": "adam"
  },
  {
    "uuid": "b745baff-312b-4d53-9438-ae28358539dc",
    "jobUuid": "d275781f-ed7f-4ce4-8f7e-a82e0e9c8f12",
    "name": "eve"
  },
  {
    "uuid": "26cba689-7eb6-4a9e-a04e-24ede0309e50",
    "name": "john",
    "jobUuid": "default",
  }
]

Sur la base des conditions mentionnées ci-dessus, est-il possible de filtrer le document dans la requête agrégée pour extraire le document d'un uuid de travail spécifique ?

Edit 1 : J'ai obtenu la solution suivante, qui fonctionne bien, je veux une meilleure solution, éliminant toutes ces étapes imbriquées.

Edit 2 : J'ai mis à jour les données avec les UUIDs réels et j'ai juste inclus seulement le name comme autre domaine, nous avons n nombre de champs qu'il n'est pas pertinent d'inclure ici mais qui sont nécessaires à la fin (à mentionner pour ceux qui veulent utiliser la projection sur tous les champs).

3voto

Veeram Points 36230

Mise à jour basée sur un commentaire :

mais les UUIDs sont des chaînes alphanumériques, comme indiqué ci-dessus, a-t-il un effet sur ce tri, et puisque nous n'utilisons pas de conditions pour obtenir les pour obtenir les résultats, je crains que cela ne pose des problèmes.

Vous pouvez utiliser un champ supplémentaire pour que l'ordre de tri soit le même que celui des valeurs de l'expression in. Assurez-vous que vous fournissez les valeurs avec la valeur par défaut comme dernière valeur.

[
  {"$match":{"jobUuid":{"$in":["d275781f-ed7f-4ce4-8f7e-a82e0e9c8f12","default"]}}},
  {"$addFields":{ "order":{"$indexOfArray":[["d275781f-ed7f-4ce4-8f7e-a82e0e9c8f12","default"], "$jobUuid"]}}},
  {"$sort":{"uuid":1, "order":1}},
  {
    "$group": {
      "_id": "$uuid",
      "doc":{"$first":"$$ROOT"}
    }
  },
  {"$project":{"doc.order":0}},
  {"$replaceRoot":{"newRoot":"$doc"}}
]

exemple ici - https://mongoplayground.net/p/wXiE9i18qxf

Original

Vous pouvez utiliser la requête ci-dessous. La requête choisira le document qui n'est pas par défaut s'il existe pour l'uuid ou bien choisira le document par défaut comme seul document.

[
  {"$match":{"jobUuid":{"$in":[1,"default"]}}},
  {"$sort":{"uuid":1, "jobUuid":1}},
  {
    "$group": {
      "_id": "$uuid",
      "doc":{"$first":"$$ROOT"}
    }
  },
  {"$replaceRoot":{"newRoot":"$doc"}}
]

exemple ici - https://mongoplayground.net/p/KrL-1s8WCpw

1voto

Deltaxfx Points 83

Voici ce que je ferais :

  1. correspond à une étape avec $in plutôt qu'un $or (pour plus de lisibilité)
  2. regrouper les étapes avec _id sur $uuid, comme vous l'avez fait, mais au lieu de pousser toutes les données dans un tableau, soyez plus sélectif. _id stocke déjà $uuid, donc aucune raison de le capturer à nouveau. Le nom doit toujours être le même pour chaque $uuid, donc ne prenez que la première instance. Sur la base de la correspondance, il n'y a que deux possibilités pour jobUuid, mais cela suppose que ce sera soit "default" ou autre chose, et qu'il peut y avoir plus d'une occurrence du jobUuid non-"default". Utiliser "$addToSet" au lieu de pousser dans un tableau au cas où il y a plusieurs occurrences du même jobUuid pour un utilisateur, aussi, avant d'ajouter à l'ensemble, utiliser une condition pour ajouter seulement les jobUuids non "par défaut", en utilisant $$REMOVE pour éviter d'insérer un null lorsque le jobUuid est "par défaut".
  3. Enfin, "$projet" pour faire le ménage. Si l'élément 0 du tableau des jobUuids n'existe pas (est nul), il n'y a pas d'autre possibilité pour cet utilisateur que d'avoir le jobUuid "default", donc utilisez "$ifNull" pour tester et définir "default" comme il convient. Il pourrait y avoir plus d'un jobUuid ici, en fonction de ce qui est autorisé dans votre base de données/application, à vous de décider comment gérer cela (prendre le plus élevé, prendre le plus bas, etc).

Testé à : https://mongoplayground.net/p/e76cVJf0F3o

[{
    "$match": {
        "jobUuid": {
            "$in": [
                "1",
                "default"
            ]
        }
    }
},
{
    "$group": {
        "_id": "$uuid",
        "name": {
            "$first": "$name"
        },
        "jobUuids": {
            "$addToSet": {
                "$cond": {
                    "if": {
                        "$ne": [
                            "$jobUuid",
                            "default"
                        ]
                    },
                    "then": "$jobUuid",
                    "else": "$$REMOVE"
                }
            }
        }
    }
},
{
    "$project": {
        "_id": 0,
        "uuid": "$_id",
        "name": 1,
        "jobUuid": {
            "$ifNull": [{
                    "$arrayElemAt": [
                        "$jobUuids",
                        0
                    ]
                },
                "default"
            ]
        }
    }
}]

0voto

kgangadhar Points 1606

J'ai pu résoudre ce problème avec la requête agrégée suivante,

  • Nous extrayons d'abord les résultats correspondant uniquement à l'élément jobUuid fourni par l'utilisateur ou le "default" dans la section des matchs.

  • Ensuite, les résultats sont regroupés sur la base de l'uuid, en utilisant une étape de groupe et nous comptons les résultats également.

  • En utilisant les conditions dans replaceRoot Nous vérifions d'abord la longueur du document groupé,

  • Si la longueur du document groupé est supérieure ou égale à 2, nous allons filtrons le document qui correspond au jobUuid fourni.

  • S'il est inférieur ou égal à 1, alors nous vérifions s'il correspond à l'objet de l'enquête. default jobUuid et le renvoie.

La requête est ci-dessous :

[
    {
      $match: {
        $or: [{ jobUuid:1 },{ jobUuid: 'default'}]
      }
    },
    {
      $group: {
        _id: '$uuid',
        count: {
          $sum: 1
        },
        docs: {
          $push: '$$ROOT'
        }
      }
    },
    {
      $replaceRoot: {
        newRoot: {
          $cond: {
            if: {
              $gte: [
                '$count',
                2
              ]
            },
            then: {
              $arrayElemAt: [
                {
                  $filter: {
                    input: '$docs',
                    as: 'item',
                    cond: {
                      $ne: [
                        '$$item.jobUuid',
                        'default'
                      ]
                    }
                  }
                },
                0
              ]
            },
            else: {
              $arrayElemAt: [
                {
                  $filter: {
                    input: '$docs',
                    as: 'item',
                    cond: {
                      $eq: [
                        '$$item.jobUuid',
                        'default'
                      ]
                    }
                  }
                },
                0
              ]
            }
          }
        }
      }
    }
  ]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X