Query for Documents With Array Size Greater Than 1 in MongoDB

Tahseen Tauseef Jan 30, 2023 Apr 28, 2022
  1. Sample Data
  2. Use the $size Operator to Query for Documents With Array Size Greater Than 1 in MongoDB
  3. Use the $where Operator to Query for Documents With Array Size Greater Than 1 in MongoDB
  4. Use Dot Notation to Query for Documents With Array Size Greater Than 1 in MongoDB
  5. Use $expr (3.6+) to Query for Documents With Array Size Greater Than 1 in MongoDB
  6. Use the Aggregation $facet Operator to Query for Documents With Array Size Greater Than 1 in MongoDB
Query for Documents With Array Size Greater Than 1 in MongoDB

When working on projects where you need to verify the array size or find an element whose size is more or less than a specific length, MongoDB operators such as $size, $where, $exists may be used.

The approaches discussed below can assist you in resolving your array length or array size issue.

Sample Data

Suppose we have the following data. We will use this sample data to query for documents with a particular array size in MongoDB.

db.inventory.insertMany([

{ item: "journal", qty: 25, tags: ["blank", "reds"], book: { author:`xyz`, price:50, location:[`india`, `USA`, `nepal`]} },

{ item: "notebook", qty: 50, tags: ["reds", "blank"], book: { author:`xyz`, price:50, location:[`india`, `usa`]} },

{ item: "paper", qty: 100, tags: ["reds", "blank", "plain"], book: { author:`xyz`, price:50, location:[]}},
{ item: "planner", qty: 75, tags: ["blank", "reds"], book: { author:`xyz`, price:50, location:[`india`]} },

{ item: "postcard", qty: 45, tags: ["blue"], book:{} }
]);

Use the $size Operator to Query for Documents With Array Size Greater Than 1 in MongoDB

The array operator class in MongoDB comprises many operators used to obtain documents by referring to arrays; $size is one of them. The $size operator is used to get a document that contains an array field of a specific size.

It only works with arrays and accepts numeric values as parameters.

The following are the $size operator’s primary functions:

  1. It starts by comparing an array field to the size given by the user, and then it continues.
  2. It retrieves the documents containing the fields that fulfill the preceding step.

Syntax:

{array-field: {$size: <length-of-array>}}

In this case, array-field is the name of the desired field in a document, and length-of-array is any numeric number that matches the length.

Some examples are shared below to see how to use the $size operator in MongoDB.

Find Elements Where tags Length Is 1

db.inventory.find({tags:{$size:1}})

Output:

$size 1

Find Elements Where books.location Length Is 1

db.inventory.find({books.location:{$size:1}}

Output:

$size 2

Use the $where Operator to Query for Documents With Array Size Greater Than 1 in MongoDB

To provide a string containing a JavaScript expression or a full JavaScript function to the query system, use the $where operator. It allows for more flexibility, but it needs the database to perform the JavaScript expression or function for every document in the collection.

Reference the record in the JavaScript expression or function using either this or obj.

Syntax:

{ $where: <string|JavaScript Code> }

Examples are given below to show the working of the $where operator.

Find Elements Where tags Length Is 1

db.inventory.find({tags:{$where:`this.tags.length == 1`}}

Output:

$where 1

Find Elements Where tags Length Is Greater Than or Equal to 1

db.inventory.find({tags:{$where:`this.tags.length >= 1`}}

Find Elements Where books.location Length Is 1

you cannot check this with the help of $where

Use the $where query operator only on top-level documents. It will not operate within a nested page.

Use Dot Notation to Query for Documents With Array Size Greater Than 1 in MongoDB

To access array elements and the fields of an embedded document, MongoDB employs dot notation.

Access Array Elements

To specify or access an array element by its zero-based index position, concatenate the array name with the dot (.) and zero-based index position, then enclose it in quotes.

Syntax:

"<array>.<index>"

For instance, consider the following field in a document.

{
   ...
   contribs: [ "Turing machine", "Turing test", "Turingery" ],
   ...
}

Use the dot notation "contribs.2" to identify the third member in the contribs.2 array.

Find Elements Where tags Length Is Greater Than 0

db.inventory.find({tags.0:{$exists:true`}}
It will look for elements with at least one tag // array with a zero-based index.

Find Elements Where books.location Length Is Greater Than 1

db.invantory.find({book.location.1: {$exists:true}}
// It looks for all components in whose book. There are at least two elements to a place.

Use $expr (3.6+) to Query for Documents With Array Size Greater Than 1 in MongoDB

Syntax:

{ $expr: { <expression> } }

Find Document Where $tags Length Is Greater Than 0

db.invantory.find({
    $expr: {
        $gt: [{ $size: { $ifNull: ["$tags", []] } }, 0]
    }
})

Find Elements Where $books.location Length Is Greater Than 1

db.invantory.find({
    $expr: {
        $gt: [{ $size: { $ifNull: ["$book.location", []] } }, 1]
    }
})
// $ifNull: ["$book.location", []] this is used to avoid any error if book.location is null

Use the Aggregation $facet Operator to Query for Documents With Array Size Greater Than 1 in MongoDB

This operator processes numerous aggregations on the same set of input documents in a single stage. Each pipeline has its field in the output document, where the results are saved as an array of documents.

The $facet stage enables the creation of multifaceted aggregations that characterize data across several dimensions, or facets, inside a single aggregation stage. Multifaceted aggregations provide multiple filters and categorizations to aid in data browsing and analysis.

For example, retailers often use faceting to reduce search results by creating filters based on product price, manufacturer, size, etc.

Input documents are only sent to the $facet step once. $facet allows for numerous aggregations on the same set of input documents without requiring them to be retrieved multiple times.

Syntax:

{ $facet:
   {
      <outputField1>: [ <stage1>, <stage2>, ... ],
      <outputField2>: [ <stage1>, <stage2>, ... ],
      ...

   }
}

Enter the name of the output field for each pipeline.

Each sub-pipeline in $facet receives the identical set of input documents. These sub-pipelines are independent of one another, and the document arrays produced by each are stored in different fields of the output document.

Within the same $facet stage, the output of one sub-pipeline cannot be utilized as the input for another sub-pipeline. Add extra stages after $facet and indicate the field name, outputField>, of the desired sub-pipeline output if further aggregations are needed.

Index Use in the $facet Stage

Even if its sub-pipelines utilize $match or if $facet is the initial step in the pipeline, the $facet stage and its sub-pipelines cannot use indexes. During execution, the $facet stage always does a COLLSCAN.

Consider an online store whose inventory is stored in the following artwork collection:

{ "_id" : 1, "title" : "The Pillars of Society", "artists" : "Grosz", "year" : 1926,
  "price" : NumberDecimal("199.99"),
  "tags" : [ "painting", "satire", "Expressionism", "caricature" ] }
{ "_id" : 2, "title" : "Melancholy III", "artists" : "Munch", "year" : 1902,
  "price" : NumberDecimal("280.00"),
  "tags" : [ "woodcut", "Expressionism" ] }
{ "_id" : 3, "title" : "Dancer", "artists" : "Miro", "year" : 1925,
  "price" : NumberDecimal("76.04"),
  "tags" : [ "oil", "Surrealism", "painting" ] }
{ "_id" : 4, "title" : "The Great Wave off Kanagawa", "artists" : "Hokusai",
  "price" : NumberDecimal("167.30"),
  "tags" : [ "woodblock", "ukiyo-e" ] }
{ "_id" : 5, "title" : "The Persistence of Memory", "artist" : "Dali", "year" : 1931,
  "price" : NumberDecimal("483.00"),
  "tags" : [ "Surrealism", "painting", "oil" ] }
{ "_id" : 6, "title" : "Composition VII", "artist" : "Kandinsky", "year" : 1913,
  "price" : NumberDecimal("385.00"),
  "tags" : [ "oil", "painting", "abstract" ] }
{ "_id" : 7, "title" : "The Scream", "artist" : "Munch", "year" : 1893,
  "tags" : [ "Expressionism", "painting", "oil" ] }
{ "_id" : 8, "title" : "Blue Flower", "artist" : "O`Keefe", "year" : 1918,
  "price" : NumberDecimal("118.42"),
  "tags" : [ "abstract", "painting" ] }

The following procedure takes advantage of MongoDB’s faceting features to show consumers the store’s inventory organized by tags, price, and year generated. This $facet stage comprises three sub-pipelines that conduct this multifaceted aggregation using $sortByCount, $bucket, or $bucketAuto.

The input documents from artwork are only retrieved from the database once, at the start of the operation.

Example:

db.artwork.aggregate( [
  {
    $facet: {
      "categorizedByTags": [
        { $unwind: "$tags" },
        { $sortByCount: "$tags" }
      ],
      "categorizedByPrice": [
        // Filter out documents without a price e.g., _id: 7
        { $match: { price: { $exists: 1 } } },
        {
          $bucket: {
            groupBy: "$price",
            boundaries: [  0, 150, 200, 300, 400 ],
            default: "Other",
            output: {
              "count": { $sum: 1 },
              "titles": { $push: "$title" }
            }
          }
        }
      ],
      "categorizedByYears(Auto)": [
        {
          $bucketAuto: {
            groupBy: "$year",
            buckets: 4
          }
        }
      ]
    }
  }
])

Output:

$facet 1

Related Article - MongoDB Query