25

I have the following documents:

{
  "dates": [
    1399518702000,
    1399126333000,
    1399209192000,
    1399027545000
  ],
  "dress_number": "4",
  "name": "J. Evans",
  "numbers": [
    "5982",
    "5983",
    "5984",
    "5985"
  ]
}

Is it possible unwind data from multiple arrays and get only paired elements from arrays:

{
    "dates": "1399518702000",
    "numbers": "5982"
},
{
    "dates": "1399126333000",
    "numbers": "5983"
},
{
    "dates": "1399209192000",
    "numbers": "5984"
},
{
    "dates": "1399027545000",
    "numbers": "5985"
}
4
  • what happen if dates array length and numbers array length not same? Commented Sep 7, 2016 at 15:11
  • They always have the same length. Commented Sep 7, 2016 at 15:12
  • The dates array element is a string "[1399518702000, 1399126333000, 1399209192000, 1399027545000]", not an array. Commented Sep 7, 2016 at 15:16
  • @chirdam, that was mistake, thank you Commented Sep 7, 2016 at 17:52

2 Answers 2

33

From version 3.2 you can do it with $unwind on both of the arrays, $cmp the indexes, and $match only the equal indexes.

This solution will populate what you wrote in case you have only the example document. If you have more documents I don't know what you expect to get in the output, but it's solvable by grouping by _id of the document.

db.test.aggregate([
    {
        $unwind: {
            path: '$dates',
            includeArrayIndex: 'dates_index',
        }
    },
    {
        $unwind: {
            path: '$numbers',
            includeArrayIndex: 'numbers_index',
        }
    },
    {
        $project: {
            dates: 1,
            numbers: 1,
            compare: {
                $cmp: ['$dates_index', '$numbers_index']
            }
        }
    },
    {
        $match: {
            compare: 0
        }
    },
    {
        $project: {
            _id: 0,
            dates: 1,
            numbers: 1
        }
    }
])
Sign up to request clarification or add additional context in comments.

3 Comments

If I understood well, it's possible to unwind a maximum of two arrays?
@corry how did you understand that? you can unwind as many as you want. The problem is that each element will become an document, so for many unwinds, the result will be enormous db. it will be very hard to handle and they question is what you want to do with them.
I think it couldn't be possible to unwind as many as I want because of $cmp operator. I put a new question regarding this problem stackoverflow.com/questions/39426022/…
5

Starting in Mongo 3.4, you can use $zip to pair your array elements:

// { values: [23, 2, 14], items: ["aa", "bb", "cc"] }
db.collection.aggregate([

  { $project: { x: { $zip: { inputs: ["$values", "$items"] } } } },
  // { x: [[23, "aa"], [2, "bb"], [14, "cc"]] }

  { $unwind: "$x" },
  // { x: [23, "aa"] }
  // { x: [2,  "bb"] }
  // { x: [14, "cc"] }

  { $project: { value: { $first: "$x" }, item: { $last: "$x" } } }
])
// { value: 23, item: "aa" }
// { value: 2,  item: "bb" }
// { value: 14, item: "cc" }

Once your arrays have been $zipped, it's just a matter of $unwinding them before creating documents out of arrays ({ value: { $first: "$x" }, item: { $last: "$x" } }).

Comments

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.