Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB unwind multiple arrays

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"
}
like image 408
corry Avatar asked Sep 07 '16 15:09

corry


People also ask

How do I unwind multiple arrays in MongoDB?

To unwind, use $unwind. The $unwind deconstructs an array field from the input documents to output a document for each element.

How do I unwind an object in MongoDB?

The MongoDB $unwind stages operator is used to deconstructing an array field from the input documents to output a document for each element. Every output document is the input document with the value of the array field replaced by the element. Points to remember: If the value of a field is not an array, db.

What is use of unwind in MongoDB?

The MongoDB $unwind operator is used to deconstruct an array field in a document and create separate output documents for each item in the array.


2 Answers

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
        }
    }
])
like image 85
TomG Avatar answered Oct 24 '22 01:10

TomG


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" } }).

like image 21
Xavier Guihot Avatar answered Oct 24 '22 02:10

Xavier Guihot