mongo: query array field size is greather than [duplicate] - mongodb

I have a MongoDB collection with documents in the following format:
{
"_id" : ObjectId("4e8ae86d08101908e1000001"),
"name" : ["Name"],
"zipcode" : ["2223"]
}
{
"_id" : ObjectId("4e8ae86d08101908e1000002"),
"name" : ["Another ", "Name"],
"zipcode" : ["2224"]
}
I can currently get documents that match a specific array size:
db.accommodations.find({ name : { $size : 2 }})
This correctly returns the documents with 2 elements in the name array. However, I can't do a $gt command to return all documents where the name field has an array size of greater than 2:
db.accommodations.find({ name : { $size: { $gt : 1 } }})
How can I select all documents with a name array of a size greater than one (preferably without having to modify the current data structure)?

There's a more efficient way to do this in MongoDB 2.2+ now that you can use numeric array indexes (0 based) in query object keys.
// Find all docs that have at least two name array elements.
db.accommodations.find({'name.1': {$exists: true}})
You can support this query with an index that uses a partial filter expression (requires 3.2+):
// index for at least two name array elements
db.accommodations.createIndex(
{'name.1': 1},
{partialFilterExpression: {'name.1': {$exists: true}}}
);

Update:
For mongodb versions 2.2+ more efficient way to do this described by #JohnnyHK in another answer.
Using $where
db.accommodations.find( { $where: "this.name.length > 1" } );
But...
Javascript executes more slowly than the native operators listed on
this page, but is very flexible. See the server-side processing page
for more information.
Create extra field NamesArrayLength, update it with names array length and then use in queries:
db.accommodations.find({"NamesArrayLength": {$gt: 1} });
It will be better solution, and will work much faster (you can create index on it).

I believe this is the fastest query that answers your question, because it doesn't use an interpreted $where clause:
{$nor: [
{name: {$exists: false}},
{name: {$size: 0}},
{name: {$size: 1}}
]}
It means "all documents except those without a name (either non existant or empty array) or with just one name."
Test:
> db.test.save({})
> db.test.save({name: []})
> db.test.save({name: ['George']})
> db.test.save({name: ['George', 'Raymond']})
> db.test.save({name: ['George', 'Raymond', 'Richard']})
> db.test.save({name: ['George', 'Raymond', 'Richard', 'Martin']})
> db.test.find({$nor: [{name: {$exists: false}}, {name: {$size: 0}}, {name: {$size: 1}}]})
{ "_id" : ObjectId("511907e3fb13145a3d2e225b"), "name" : [ "George", "Raymond" ] }
{ "_id" : ObjectId("511907e3fb13145a3d2e225c"), "name" : [ "George", "Raymond", "Richard" ] }
{ "_id" : ObjectId("511907e3fb13145a3d2e225d"), "name" : [ "George", "Raymond", "Richard", "Martin" ] }
>

You can use aggregate, too:
db.accommodations.aggregate(
[
{$project: {_id:1, name:1, zipcode:1,
size_of_name: {$size: "$name"}
}
},
{$match: {"size_of_name": {$gt: 1}}}
])
// you add "size_of_name" to transit document and use it to filter the size of the name

You can use $expr ( 3.6 mongo version operator ) to use aggregation functions in regular query.
Compare query operators vs aggregation comparison operators.
db.accommodations.find({$expr:{$gt:[{$size:"$name"}, 1]}})

Try to do something like this:
db.getCollection('collectionName').find({'ArrayName.1': {$exists: true}})
1 is number, if you want to fetch record greater than 50 then do ArrayName.50
Thanks.

MongoDB 3.6 include $expr
https://docs.mongodb.com/manual/reference/operator/query/expr/
You can use $expr in order to evaluate an expression inside a $match, or find.
{ $match: {
$expr: {$gt: [{$size: "$yourArrayField"}, 0]}
}
}
or find
collection.find({$expr: {$gte: [{$size: "$yourArrayField"}, 0]}});

None of the above worked for me. This one did so I'm sharing it:
db.collection.find( {arrayName : {$exists:true}, $where:'this.arrayName.length>1'} )

db.accommodations.find({"name":{"$exists":true, "$ne":[], "$not":{"$size":1}}})

Although the above answers all work, What you originally tried to do was the correct way, however you just have the syntax backwards (switch "$size" and "$gt")..
Correct:
db.collection.find({items: {$gt: {$size: 1}}})

I found this solution, to find items with an array field greater than certain length
db.allusers.aggregate([
{$match:{username:{$exists:true}}},
{$project: { count: { $size:"$locations.lat" }}},
{$match:{count:{$gt:20}}}
])
The first $match aggregate uses an argument thats true for all the documents. If blank, i would get
"errmsg" : "exception: The argument to $size must be an Array, but was of type: EOO"

You can MongoDB aggregation to do the task:
db.collection.aggregate([
{
$addFields: {
arrayLength: {$size: '$array'}
},
},
{
$match: {
arrayLength: {$gt: 1}
},
},
])

This will work in Compass also. This is the fastest of all i have tried without indexing.
{$expr: {
$gt: [
{
$size: { "$ifNull": [ "$name", [] ] }
},
1
]
}}

you can use $expr to cover this
// $expr: Allows the use of aggregation expressions within the query language.
// syntax: {$expr: {<expression>}}
db.getCollection("person_service").find(
{
"$expr" : {
// services is Array, find services length gt 3
"$gt" : [
{
"$size" : "$services"
},
3.0
]
}
}
)

Related

MongoDB: How to match on the elements of an array?

I have two collections as follows:
db.qnames.find()
{ "_id" : ObjectId("5a4da53f97a9ca769a15d49e"), "domain" : "mail.google.com", "tldOne" : "google.com", "clients" : 10, "date" : "2016-12-30" }
{ "_id" : ObjectId("5a4da55497a9ca769a15d49f"), "domain" : "mail.google.com", "tldOne" : "google.com", "clients" : 9, "date" : "2017-01-30” }
and
db.dropped.find()
{ "_id" : ObjectId("5a4da4ac97a9ca769a15d49c"), "domain" : "google.com", "dropDate" : "2017-01-01", "regStatus" : 1 }
I would like to join the two collections and choose the documents for which 'dropDate' field (from dropped collection) is larger than the 'date' filed (from qnames field). So I used the following query:
db.dropped.aggregate( [{$lookup:{ from:"qnames", localField:"domain",foreignField:"tldOne",as:"droppedTraffic"}},
{$match: {"droppedTraffic":{$ne:[]} }},
{$unwind: "$droppedTraffic" } ,
{$match: {dropDate:{$gt:"$droppedTraffic.date"}}} ])
but this query does not filter the records where dropDate < date. Anyone can give me a clue of why it happens?
The reason why you are not getting the record is
Date is used as a String in your collections, to make use of the comparison operators to get the desired result modify your collection documents using new ISODate("your existing date in the collection")
Please note even after modifying both the collections you need to modify your aggregate query, since in the final $match query two values from the same document is been compared.
Sample query to get the desired documents
db.dropped.aggregate([
{$lookup: {
from:"qnames",
localField:"domain",
foreignField:"tldOne",
as:"droppedTraffic"}
},
{$project: {
_id:1, domain:1,
regStatus:1,
droppedTraffic: {
$filter: {
input: "$droppedTraffic",
as:"droppedTraffic",
cond:{ $gt: ["$$droppedTraffic.date", "$dropDate"]}
}
}
}}
])
In this approach given above we have used $filter which avoids the $unwind operation
You should use $redact to compare two fields of the same document. Following example should work:
db.dropped.aggregate( [
{$lookup:{ from:"qnames", localField:"domain",foreignField:"tldOne",as:"droppedTraffic"}},
{$match: {"droppedTraffic":{$ne:[]} }},
{$unwind: "$droppedTraffic" },
{
"$redact": {
"$cond": [
{ "$lte": [ "$dropDate", "$droppedTraffic.date" ] },
"$$KEEP",
"$$PRUNE"
]
}
}
])

Counting the email and phone more than 3 and showing the output as _id,email count,phone count [duplicate]

I have a MongoDB collection with documents in the following format:
{
"_id" : ObjectId("4e8ae86d08101908e1000001"),
"name" : ["Name"],
"zipcode" : ["2223"]
}
{
"_id" : ObjectId("4e8ae86d08101908e1000002"),
"name" : ["Another ", "Name"],
"zipcode" : ["2224"]
}
I can currently get documents that match a specific array size:
db.accommodations.find({ name : { $size : 2 }})
This correctly returns the documents with 2 elements in the name array. However, I can't do a $gt command to return all documents where the name field has an array size of greater than 2:
db.accommodations.find({ name : { $size: { $gt : 1 } }})
How can I select all documents with a name array of a size greater than one (preferably without having to modify the current data structure)?
There's a more efficient way to do this in MongoDB 2.2+ now that you can use numeric array indexes (0 based) in query object keys.
// Find all docs that have at least two name array elements.
db.accommodations.find({'name.1': {$exists: true}})
You can support this query with an index that uses a partial filter expression (requires 3.2+):
// index for at least two name array elements
db.accommodations.createIndex(
{'name.1': 1},
{partialFilterExpression: {'name.1': {$exists: true}}}
);
Update:
For mongodb versions 2.2+ more efficient way to do this described by #JohnnyHK in another answer.
Using $where
db.accommodations.find( { $where: "this.name.length > 1" } );
But...
Javascript executes more slowly than the native operators listed on
this page, but is very flexible. See the server-side processing page
for more information.
Create extra field NamesArrayLength, update it with names array length and then use in queries:
db.accommodations.find({"NamesArrayLength": {$gt: 1} });
It will be better solution, and will work much faster (you can create index on it).
I believe this is the fastest query that answers your question, because it doesn't use an interpreted $where clause:
{$nor: [
{name: {$exists: false}},
{name: {$size: 0}},
{name: {$size: 1}}
]}
It means "all documents except those without a name (either non existant or empty array) or with just one name."
Test:
> db.test.save({})
> db.test.save({name: []})
> db.test.save({name: ['George']})
> db.test.save({name: ['George', 'Raymond']})
> db.test.save({name: ['George', 'Raymond', 'Richard']})
> db.test.save({name: ['George', 'Raymond', 'Richard', 'Martin']})
> db.test.find({$nor: [{name: {$exists: false}}, {name: {$size: 0}}, {name: {$size: 1}}]})
{ "_id" : ObjectId("511907e3fb13145a3d2e225b"), "name" : [ "George", "Raymond" ] }
{ "_id" : ObjectId("511907e3fb13145a3d2e225c"), "name" : [ "George", "Raymond", "Richard" ] }
{ "_id" : ObjectId("511907e3fb13145a3d2e225d"), "name" : [ "George", "Raymond", "Richard", "Martin" ] }
>
You can use aggregate, too:
db.accommodations.aggregate(
[
{$project: {_id:1, name:1, zipcode:1,
size_of_name: {$size: "$name"}
}
},
{$match: {"size_of_name": {$gt: 1}}}
])
// you add "size_of_name" to transit document and use it to filter the size of the name
You can use $expr ( 3.6 mongo version operator ) to use aggregation functions in regular query.
Compare query operators vs aggregation comparison operators.
db.accommodations.find({$expr:{$gt:[{$size:"$name"}, 1]}})
Try to do something like this:
db.getCollection('collectionName').find({'ArrayName.1': {$exists: true}})
1 is number, if you want to fetch record greater than 50 then do ArrayName.50
Thanks.
MongoDB 3.6 include $expr
https://docs.mongodb.com/manual/reference/operator/query/expr/
You can use $expr in order to evaluate an expression inside a $match, or find.
{ $match: {
$expr: {$gt: [{$size: "$yourArrayField"}, 0]}
}
}
or find
collection.find({$expr: {$gte: [{$size: "$yourArrayField"}, 0]}});
None of the above worked for me. This one did so I'm sharing it:
db.collection.find( {arrayName : {$exists:true}, $where:'this.arrayName.length>1'} )
db.accommodations.find({"name":{"$exists":true, "$ne":[], "$not":{"$size":1}}})
Although the above answers all work, What you originally tried to do was the correct way, however you just have the syntax backwards (switch "$size" and "$gt")..
Correct:
db.collection.find({items: {$gt: {$size: 1}}})
I found this solution, to find items with an array field greater than certain length
db.allusers.aggregate([
{$match:{username:{$exists:true}}},
{$project: { count: { $size:"$locations.lat" }}},
{$match:{count:{$gt:20}}}
])
The first $match aggregate uses an argument thats true for all the documents. If blank, i would get
"errmsg" : "exception: The argument to $size must be an Array, but was of type: EOO"
You can MongoDB aggregation to do the task:
db.collection.aggregate([
{
$addFields: {
arrayLength: {$size: '$array'}
},
},
{
$match: {
arrayLength: {$gt: 1}
},
},
])
This will work in Compass also. This is the fastest of all i have tried without indexing.
{$expr: {
$gt: [
{
$size: { "$ifNull": [ "$name", [] ] }
},
1
]
}}
you can use $expr to cover this
// $expr: Allows the use of aggregation expressions within the query language.
// syntax: {$expr: {<expression>}}
db.getCollection("person_service").find(
{
"$expr" : {
// services is Array, find services length gt 3
"$gt" : [
{
"$size" : "$services"
},
3.0
]
}
}
)

How can I find items with a field including N values inside? [duplicate]

I have a MongoDB collection with documents in the following format:
{
"_id" : ObjectId("4e8ae86d08101908e1000001"),
"name" : ["Name"],
"zipcode" : ["2223"]
}
{
"_id" : ObjectId("4e8ae86d08101908e1000002"),
"name" : ["Another ", "Name"],
"zipcode" : ["2224"]
}
I can currently get documents that match a specific array size:
db.accommodations.find({ name : { $size : 2 }})
This correctly returns the documents with 2 elements in the name array. However, I can't do a $gt command to return all documents where the name field has an array size of greater than 2:
db.accommodations.find({ name : { $size: { $gt : 1 } }})
How can I select all documents with a name array of a size greater than one (preferably without having to modify the current data structure)?
There's a more efficient way to do this in MongoDB 2.2+ now that you can use numeric array indexes (0 based) in query object keys.
// Find all docs that have at least two name array elements.
db.accommodations.find({'name.1': {$exists: true}})
You can support this query with an index that uses a partial filter expression (requires 3.2+):
// index for at least two name array elements
db.accommodations.createIndex(
{'name.1': 1},
{partialFilterExpression: {'name.1': {$exists: true}}}
);
Update:
For mongodb versions 2.2+ more efficient way to do this described by #JohnnyHK in another answer.
Using $where
db.accommodations.find( { $where: "this.name.length > 1" } );
But...
Javascript executes more slowly than the native operators listed on
this page, but is very flexible. See the server-side processing page
for more information.
Create extra field NamesArrayLength, update it with names array length and then use in queries:
db.accommodations.find({"NamesArrayLength": {$gt: 1} });
It will be better solution, and will work much faster (you can create index on it).
I believe this is the fastest query that answers your question, because it doesn't use an interpreted $where clause:
{$nor: [
{name: {$exists: false}},
{name: {$size: 0}},
{name: {$size: 1}}
]}
It means "all documents except those without a name (either non existant or empty array) or with just one name."
Test:
> db.test.save({})
> db.test.save({name: []})
> db.test.save({name: ['George']})
> db.test.save({name: ['George', 'Raymond']})
> db.test.save({name: ['George', 'Raymond', 'Richard']})
> db.test.save({name: ['George', 'Raymond', 'Richard', 'Martin']})
> db.test.find({$nor: [{name: {$exists: false}}, {name: {$size: 0}}, {name: {$size: 1}}]})
{ "_id" : ObjectId("511907e3fb13145a3d2e225b"), "name" : [ "George", "Raymond" ] }
{ "_id" : ObjectId("511907e3fb13145a3d2e225c"), "name" : [ "George", "Raymond", "Richard" ] }
{ "_id" : ObjectId("511907e3fb13145a3d2e225d"), "name" : [ "George", "Raymond", "Richard", "Martin" ] }
>
You can use aggregate, too:
db.accommodations.aggregate(
[
{$project: {_id:1, name:1, zipcode:1,
size_of_name: {$size: "$name"}
}
},
{$match: {"size_of_name": {$gt: 1}}}
])
// you add "size_of_name" to transit document and use it to filter the size of the name
You can use $expr ( 3.6 mongo version operator ) to use aggregation functions in regular query.
Compare query operators vs aggregation comparison operators.
db.accommodations.find({$expr:{$gt:[{$size:"$name"}, 1]}})
Try to do something like this:
db.getCollection('collectionName').find({'ArrayName.1': {$exists: true}})
1 is number, if you want to fetch record greater than 50 then do ArrayName.50
Thanks.
MongoDB 3.6 include $expr
https://docs.mongodb.com/manual/reference/operator/query/expr/
You can use $expr in order to evaluate an expression inside a $match, or find.
{ $match: {
$expr: {$gt: [{$size: "$yourArrayField"}, 0]}
}
}
or find
collection.find({$expr: {$gte: [{$size: "$yourArrayField"}, 0]}});
None of the above worked for me. This one did so I'm sharing it:
db.collection.find( {arrayName : {$exists:true}, $where:'this.arrayName.length>1'} )
db.accommodations.find({"name":{"$exists":true, "$ne":[], "$not":{"$size":1}}})
Although the above answers all work, What you originally tried to do was the correct way, however you just have the syntax backwards (switch "$size" and "$gt")..
Correct:
db.collection.find({items: {$gt: {$size: 1}}})
I found this solution, to find items with an array field greater than certain length
db.allusers.aggregate([
{$match:{username:{$exists:true}}},
{$project: { count: { $size:"$locations.lat" }}},
{$match:{count:{$gt:20}}}
])
The first $match aggregate uses an argument thats true for all the documents. If blank, i would get
"errmsg" : "exception: The argument to $size must be an Array, but was of type: EOO"
You can MongoDB aggregation to do the task:
db.collection.aggregate([
{
$addFields: {
arrayLength: {$size: '$array'}
},
},
{
$match: {
arrayLength: {$gt: 1}
},
},
])
This will work in Compass also. This is the fastest of all i have tried without indexing.
{$expr: {
$gt: [
{
$size: { "$ifNull": [ "$name", [] ] }
},
1
]
}}
you can use $expr to cover this
// $expr: Allows the use of aggregation expressions within the query language.
// syntax: {$expr: {<expression>}}
db.getCollection("person_service").find(
{
"$expr" : {
// services is Array, find services length gt 3
"$gt" : [
{
"$size" : "$services"
},
3.0
]
}
}
)

Query for documents where array size is greater than 1

I have a MongoDB collection with documents in the following format:
{
"_id" : ObjectId("4e8ae86d08101908e1000001"),
"name" : ["Name"],
"zipcode" : ["2223"]
}
{
"_id" : ObjectId("4e8ae86d08101908e1000002"),
"name" : ["Another ", "Name"],
"zipcode" : ["2224"]
}
I can currently get documents that match a specific array size:
db.accommodations.find({ name : { $size : 2 }})
This correctly returns the documents with 2 elements in the name array. However, I can't do a $gt command to return all documents where the name field has an array size of greater than 2:
db.accommodations.find({ name : { $size: { $gt : 1 } }})
How can I select all documents with a name array of a size greater than one (preferably without having to modify the current data structure)?
There's a more efficient way to do this in MongoDB 2.2+ now that you can use numeric array indexes (0 based) in query object keys.
// Find all docs that have at least two name array elements.
db.accommodations.find({'name.1': {$exists: true}})
You can support this query with an index that uses a partial filter expression (requires 3.2+):
// index for at least two name array elements
db.accommodations.createIndex(
{'name.1': 1},
{partialFilterExpression: {'name.1': {$exists: true}}}
);
Update:
For mongodb versions 2.2+ more efficient way to do this described by #JohnnyHK in another answer.
Using $where
db.accommodations.find( { $where: "this.name.length > 1" } );
But...
Javascript executes more slowly than the native operators listed on
this page, but is very flexible. See the server-side processing page
for more information.
Create extra field NamesArrayLength, update it with names array length and then use in queries:
db.accommodations.find({"NamesArrayLength": {$gt: 1} });
It will be better solution, and will work much faster (you can create index on it).
I believe this is the fastest query that answers your question, because it doesn't use an interpreted $where clause:
{$nor: [
{name: {$exists: false}},
{name: {$size: 0}},
{name: {$size: 1}}
]}
It means "all documents except those without a name (either non existant or empty array) or with just one name."
Test:
> db.test.save({})
> db.test.save({name: []})
> db.test.save({name: ['George']})
> db.test.save({name: ['George', 'Raymond']})
> db.test.save({name: ['George', 'Raymond', 'Richard']})
> db.test.save({name: ['George', 'Raymond', 'Richard', 'Martin']})
> db.test.find({$nor: [{name: {$exists: false}}, {name: {$size: 0}}, {name: {$size: 1}}]})
{ "_id" : ObjectId("511907e3fb13145a3d2e225b"), "name" : [ "George", "Raymond" ] }
{ "_id" : ObjectId("511907e3fb13145a3d2e225c"), "name" : [ "George", "Raymond", "Richard" ] }
{ "_id" : ObjectId("511907e3fb13145a3d2e225d"), "name" : [ "George", "Raymond", "Richard", "Martin" ] }
>
You can use aggregate, too:
db.accommodations.aggregate(
[
{$project: {_id:1, name:1, zipcode:1,
size_of_name: {$size: "$name"}
}
},
{$match: {"size_of_name": {$gt: 1}}}
])
// you add "size_of_name" to transit document and use it to filter the size of the name
You can use $expr ( 3.6 mongo version operator ) to use aggregation functions in regular query.
Compare query operators vs aggregation comparison operators.
db.accommodations.find({$expr:{$gt:[{$size:"$name"}, 1]}})
Try to do something like this:
db.getCollection('collectionName').find({'ArrayName.1': {$exists: true}})
1 is number, if you want to fetch record greater than 50 then do ArrayName.50
Thanks.
MongoDB 3.6 include $expr
https://docs.mongodb.com/manual/reference/operator/query/expr/
You can use $expr in order to evaluate an expression inside a $match, or find.
{ $match: {
$expr: {$gt: [{$size: "$yourArrayField"}, 0]}
}
}
or find
collection.find({$expr: {$gte: [{$size: "$yourArrayField"}, 0]}});
None of the above worked for me. This one did so I'm sharing it:
db.collection.find( {arrayName : {$exists:true}, $where:'this.arrayName.length>1'} )
db.accommodations.find({"name":{"$exists":true, "$ne":[], "$not":{"$size":1}}})
Although the above answers all work, What you originally tried to do was the correct way, however you just have the syntax backwards (switch "$size" and "$gt")..
Correct:
db.collection.find({items: {$gt: {$size: 1}}})
I found this solution, to find items with an array field greater than certain length
db.allusers.aggregate([
{$match:{username:{$exists:true}}},
{$project: { count: { $size:"$locations.lat" }}},
{$match:{count:{$gt:20}}}
])
The first $match aggregate uses an argument thats true for all the documents. If blank, i would get
"errmsg" : "exception: The argument to $size must be an Array, but was of type: EOO"
You can MongoDB aggregation to do the task:
db.collection.aggregate([
{
$addFields: {
arrayLength: {$size: '$array'}
},
},
{
$match: {
arrayLength: {$gt: 1}
},
},
])
This will work in Compass also. This is the fastest of all i have tried without indexing.
{$expr: {
$gt: [
{
$size: { "$ifNull": [ "$name", [] ] }
},
1
]
}}
you can use $expr to cover this
// $expr: Allows the use of aggregation expressions within the query language.
// syntax: {$expr: {<expression>}}
db.getCollection("person_service").find(
{
"$expr" : {
// services is Array, find services length gt 3
"$gt" : [
{
"$size" : "$services"
},
3.0
]
}
}
)

Querying internal array size in MongoDB

Consider a MongoDB document in users collection:
{ username : 'Alex', tags: ['C#', 'Java', 'C++'] }
Is there any way, to get the length of the tags array from the server side (without passing the tags to the client) ?
Thank you!
if username Alex is unique, you can use next code:
db.test.insert({username:"Alex", tags: ['C#', 'Java', 'C++'] });
db.test.aggregate(
{$match: {username : "Alex"}},
{$unwind: "$tags"},
{$project: {count:{$add:1}}},
{$group: {_id: null, number: {$sum: "$count" }}}
);
{ "result" : [ { "_id" : null, "number" : 3 } ], "ok" : 1 }
Now MongoDB (2.6 release) supports $size operation in aggregation.
From the documentation:
{ <field>: { $size: <array> } }
What you want can be accomplished as following with either by using this:
db.users.aggregate(
[
{
$group: {
_id: "$username",
tags_count: {$first: {$size: "$tags" }}
}
}
]
)
or
db.users.aggregate(
[
{
$project: {
tags_count: {$size: "$tags"}
}
}
]
)
I think it might be more efficient to calculate the number of tags on each save (as a separate field) using $inc perhaps or via a job on a schedule.
You could also do this with map/reduce (the canonical example) but that doesn't seem to be be what you'd want.
I'm not sure it's possible to do exactly what you are asking, but you can query all the documents that match a certain size with $size ...
> db.collection.find({ tags : { $size: 3 }});
That'd get you all the documents with 3 tags ...
xmm.dev's answer can be simplified: instead of having interm field 'count', you can sum directly in $group:
db.test.aggregate(
{$match: {username : "Alex"}},
{$unwind: "$tags"},
{$group: {_id: null, number: {$sum: 1 }}}
)
Currently, the only way to do it seems to be using db.eval, but this locks database for other operations.
The most speed-efficient way would be adding an extra field that stores the length of the array and
maintaining it by $inc and $push operations.
I did a small work around as I needed to query the array size and return if it was greater than 0 but could be anything from 1-3.
Here was my solution:
db.test.find($or : [{$field : { $exists : true, $size : 1}},
{$field : { $exists : true, $size : 2}},
{$field : { $exists : true, $size : 3}}, ])
This basically returns a document when the attribute exists and the size is 1, 2, or 3. The user can add more statements and increment if they are looking for a specific size or within a range. I know its not perfect but it did work and was relatively quick. I only had 1-3 sizes in my attribute so this solution worked.