1

Basically, I have a nested array of objects. I want to extract information from those objects, and return all the results as an array.

Here is my data:

[
  {
    "_id": "608642db80a36336946620aa",
    "title": "titleHere",
    "types": {
      "flashcardReversed": [
        {
          "normal": { // the data inside of "normal" should become its own object in the returned array
            "_id": "608d5b290e635ece6828141X",
            "front": "2front",
            "back": "2back"
          },
          "reversed": { // the data inside of "reversed" should become its own object in the returned array
            "_id": "608t5b290e635ece6828141Y",
            "front": "2frontReversed",
            "back": "2backReversed"
          }
        },
        {
          "normal": {
            "_id": "608a5b31a3f9806de253726X",
            "front": "2front2",
            "back": "2back2"
          },
          "reversed": {
            "_id": "608a5b31a3f9806de253726Y",
            "front": "2frontReversed2",
            "back": "2backReversed2"
          }
        }
      ]
    }
  }
]

Here is the desired result:

[
  {
    "flashcardReversed": [
      {
        "_id": "608d5b290e635ece6828141X",
        "front": "2front",
        "back": "2back"
      },
      {
        "_id": "608t5b290e635ece6828141Y",
        "front": "2frontReversed",
        "back": "2backReversed"
      },
      {
        "_id": "608t5b290e635ece6828141Y",
        "front": "2frontReversed",
        "back": "2backReversed"
      },
      {
        "_id": "608a5b31a3f9806de253726Y",
        "front": "2frontReversed2",
        "back": "2backReversed2"
      }
    ]
  }
]

My current attempt: https://mongoplayground.net/p/k3Fjd59KMKg I have tried merging the $card and $card2 documents through various methods, and then using $replaceRoot to create the desired result - but after much time trying, I was unsuccessful.

Some notes about my use-case - I will be using this pipeline inside $facet There will be many objects inside of flashcardReversed, all created from the same Mongoose Schema

The document should have a max of ~2000 cards. I need the results for use in a react website. Should I be worried about the efficiency of this search? (if this should be a question in itself I would be happy to move it).

If my Mongoose Schemas would be helpful, let me know and I can add them.

All help is appreciated,

- Riley Swinson

2
  • Is it always "normal" and "reversed" keys in the original? Or can there be more ? Commented May 5, 2021 at 1:47
  • @CodyG there can be many documents, all with the same structure. I'll clarify my post. Thanks! Commented May 5, 2021 at 1:47

2 Answers 2

2

I was able to come up with this query to get the desired result

    db.collection.aggregate([
  {
    "$unwind": "$types.flashcardReversed"
  },
  {
    "$project": {
      "flashcardReversed": {
        "$map": {
          "input": {
            "$objectToArray": "$types.flashcardReversed"
          },
          "as": "elem",
          "in": "$$elem.v"
        }
      }
    }
  },
  {
    "$unwind": "$flashcardReversed"
  },
  {
    "$group": {
      "_id": 1,
      "flashcardReversed": {
        "$push": "$flashcardReversed"
      }
    }
  },
  {
    "$project": {
      "_id": 0
    }
  }
])

Explanation of the above pipeline :

  1. Use $unwind to divide the array into its elements
  2. Use $project along with $map to convert the flashcardReversed object into an array of values. Using $map allows the pipeline to handle any additional keys on top of normal and reversed
  3. Use $unwind to again split the flashcardReversed array formed in step 2
  4. Use $group with the $push accumulator to add all values of flashcardReversed in a single array
  5. Use $project to remove the _id field from the response

Here's a Mongodb playground link for the same

Sign up to request clarification or add additional context in comments.

Comments

1

This can be done with

  • $unwind to split the flash card array
  • $project to convert the object containing normal/reverse to an array
  • $unwind the created array
  • $group by _id and collect the values in an array
db.collection.aggregate([
  {$unwind: "$types.flashcardReversed"},
  {$project: {
      flashcardReversed: [
        "$types.flashcardReversed.normal",
        "$types.flashcardReversed.reversed"
      ]
  }},
  {$unwind: "$flashcardReversed"},
  {$group: {
      _id: "$_id",
      flashcardReversed: {$push: "$flashcardReversed"}
  }}
])

7 Comments

Thanks for answering - I appreciate it. I noticed an error in my question - because I am using $facet, I already have"flashcardReversed" as the parent: []. How would I return just what is inside of the flashcardReversed array in your result?
Use a $replaceRoot stage
tried, but got error $replaceRoot must be of type object. Attempted to use $arrayToObject, but I think I need a different object structure for that to work?
{$replaceRoot:{newRoot:"$flashcardReversed"}}
Yes, exactly what I tried, and still returns an error - mongoplayground.net/p/CiaOOrzzw5i. The goal would be to remove all the contents from the array - since $facet is already an array this seems like it could be a solution
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.