Get nested document field values, transform them and write them as a new field in the nested document

Hello all,

I have the following data structure:

And I have lots of such locations with lots of such nested events.

I am trying to figure out how to get every event name, transform it with a JS function that I have, and write it back into new slug field inside the same event?

Every bit of help would be much appreciated!

So far I’ve tried with aggregation but I had no success. I’ve tried also getting each location, extracting the events, getting their names and transforming them into slugs. For each location I end up having an array of slugs for which I cannot figure out how to write them back inside the corresponding event.

Thank you!

Regards

Please read Formatting code and log snippets in posts and update your sample documents so that we can cut-n-paste into our system.

Also share the expected result.

Share what you tried and how it failed so that we can avoid experimenting in a direction you already know that fails.

This is an example location from my collection.

{
  "_id": { "$oid": "61fe9b6a390bd807cb3f8258" },
  "name": "Spectrum Center",
  "coords": {
    "lat": { "$numberDouble": "35.225088" },
    "long": { "$numberDouble": "-80.8397" }
  },
  "address": "333 E Trade St",
  "country": "USA",
  "city": "Charlotte",
  "category": "concert",
  "events": [
    {
      "name": "ANUEL AA: LEGENDS NEVER DIE WORLD TOUR",
      "image": "",
      "link": "",
      "date": "2022-10-08",
      "time": "20:00",
      "expiresAt": { "$numberDouble": "1.6653456000000E+12" },
      "_location": { "$oid": "61fe9b6a390bd807cb3f8258" },
      "_id": { "$oid": "624ef91f5030c078c684e572" }
    },
    {
      "name": "Greta Van Fleet - Dreams In Gold Tour 2022",
      "image": "",
      "link": "",
      "date": "2022-10-28",
      "time": "19:00",
      "expiresAt": { "$numberDouble": "1.6670700000000E+12" },
      "_location": { "$oid": "61fe9b6a390bd807cb3f8258" },
      "_id": { "$oid": "62703fd9e9212167a21e153c" }
    },
    {
      "name": "Daddy Yankee La Última Vuelta World Tour",
      "image": "",
      "link": "",
      "date": "2022-12-06",
      "time": "20:00",
      "expiresAt": { "$numberDouble": "1.6704432000000E+12" },
      "_location": { "$oid": "61fe9b6a390bd807cb3f8258" },
      "_id": { "$oid": "628ea28b50b698ff61909c13" }
    },
    {
      "name": "Lizzo: The Special Tour",
      "image": "",
      "link": "",
      "date": "2022-10-20",
      "time": "20:00",
      "expiresAt": { "$numberDouble": "1.6663824000000E+12" },
      "_location": { "$oid": "61fe9b6a390bd807cb3f8258" },
      "_id": { "$oid": "628ea2c150b698ff61909c24" }
    }
  ],
  "__v": { "$numberInt": "0" },
  "slug": "spectrum-center"
}

What I am trying to do is transforming it into:


{
  "_id": { "$oid": "61fe9b6a390bd807cb3f8258" },
  "name": "Spectrum Center",
  "coords": {
    "lat": { "$numberDouble": "35.225088" },
    "long": { "$numberDouble": "-80.8397" }
  },
  "address": "333 E Trade St",
  "country": "USA",
  "city": "Charlotte",
  "category": "concert",
  "events": [
    {
      "name": "ANUEL AA: LEGENDS NEVER DIE WORLD TOUR",
      "image": "",
      "link": "",
      "date": "2022-10-08",
      "time": "20:00",
      "slug": "anuel-aa-legends-never-die-world-tour",
      "expiresAt": { "$numberDouble": "1.6653456000000E+12" },
      "_location": { "$oid": "61fe9b6a390bd807cb3f8258" },
      "_id": { "$oid": "624ef91f5030c078c684e572" }
    },
    {
      "name": "Greta Van Fleet - Dreams In Gold Tour 2022",
      "image": "",
      "link": "",
      "date": "2022-10-28",
      "time": "19:00",
      "slug": "greta-van-fleet-dreams-in-gold-tour-2022",
      "expiresAt": { "$numberDouble": "1.6670700000000E+12" },
      "_location": { "$oid": "61fe9b6a390bd807cb3f8258" },
      "_id": { "$oid": "62703fd9e9212167a21e153c" }
    },
    {
      "name": "Daddy Yankee La Última Vuelta World Tour",
      "image": "",
      "link": "",
      "date": "2022-12-06",
      "time": "20:00",
      "slug": "daddy-yankee-la-ultima-vuelta-world-tour",
      "expiresAt": { "$numberDouble": "1.6704432000000E+12" },
      "_location": { "$oid": "61fe9b6a390bd807cb3f8258" },
      "_id": { "$oid": "628ea28b50b698ff61909c13" }
    },
    {
      "name": "Lizzo: The Special Tour",
      "image": "",
      "link": "",
      "date": "2022-10-20",
      "time": "20:00",
      "slug": "lizzo-the-special-tour",
      "expiresAt": { "$numberDouble": "1.6663824000000E+12" },
      "_location": { "$oid": "61fe9b6a390bd807cb3f8258" },
      "_id": { "$oid": "628ea2c150b698ff61909c24" }
    }
  ],
  "__v": { "$numberInt": "0" },
  "slug": "spectrum-center"
}

Notice how for every event there is a slug added, which is the name of the event transformed into slug.

I have a JS function that can transform the event name strings into the event slug strings, however I do not know how to access every event name separately, transform it with my function and add the output slug string inside the event object.

Here is also a screenshot of my db, collections, etc.:

So far I’ve tried following approaches:

locations.aggregate([
    {
      $unwind: "$events",
    },
    {
      $addFields: {
        "events.slug": {
          $function: { body: string_to_slug, args: "$events.name", lang: "js" },
        },
      },
    },
   { $out: "events_with_slugs" }
  ]);

Here the string_to_slug function is my JS function which transforms an event name string into event slug string. But this approach is not working. Or at least I do not know how to group it all.

The other thing that I’ve tried was to get all event names as an array and transform them into array of slugs … but I do not know how to insert them into the events afterwards:

  locations.distinct("name", function (err, docs) {
    docs.map(async (doc) => {
      const location = await locations.findOne({ name: doc });

      const location_events = location.events;
      const names = location_events.map(({ name }) => {
        return name;
      });
      const slugs = names.map((name) => {
        return string_to_slug(name);
      });

      //-------------------------
     //here I do not know how to insert the slugs into the respective event
    });
  });

I hope with this code snippets and the screenshot of my data it is bit clearer what I am trying to achieve.

Regards

1 Like

Thanks, we can definitively experiment with this.

Hi,

I think I have some progress. I’ve tried:

locations.aggregate([
      {
        $unwind: "$events",
      },
      {
        $addFields: {
          "events.slug": {
            $function: {
              body: string_to_slug,
              args: ["$events.name"],
              lang: "js",
            },
          },
        },
      },
      {
        $group: {
          _id: "$_id",
          name: {
            $first: "$name",
          },
          address: {
            $first: "$address",
          },
          coords: {
            $first: "$coords",
          },
          city: {
            $first: "$city",
          },
          country: {
            $first: "$country",
          },
          category: {
            $first: "$category",
          },
          slug: {
            $first: "$slug",
          },
          events: {
            $push: "$events",
          },
        },
      },
     {
        $out: "events_with_slugs",
      },
    ]);

It seems to work, but the amount of the output documents is far smaller than the original amount. This is maybe because there are lots of locations with no events inside.

The question now is how to get also those in the final result?