MongoDb - Can you use $bitsAllSet in an aggregate projection or group? - mongodb

I have a field stored in a mongo collection that is an integer bitmask, and I frequently use the $bitsAllSet query operator to find documents where certain bit flags are set.
Now I would like to do an aggregation to get counts of documents for each bit flag. I figured I would start by trying to project if the bit is set or not.
Something like..
db.MyCollection.aggregate(
[
{ $project: {
bit1: { $bitsAllSet: ["$myBitMask", 1] },
bit2: { $bitsAllSet: ["$myBitMask", 2] },
bit3: { $bitsAllSet: ["$myBitMask", 4] },
bit4: { $bitsAllSet: ["$myBitMask", 8] }
} }
])
but this is invalid syntax and I cannot find anything in the mongo documentation that looks like it would help me accomplish this.
Is there a way achieve this?

Related

MongoDB: Remove certain number of elements from start of an array

Is there a way to remove certain amounts of elements from start of an array in MongoDB?
Suppose I don't know about element's details (like id or uuid) but I know that I want to remove the first N elements from the start of it. Is there a way to do it in mongoDB? I know I can fetch the whole document and process it in my own programming language environment but I thought it would be nicer if mongoDB already implemented a way to achieve it atomically by its own query language.
There is a $pop operator to remove a single element from the array either from top or bottom position,
and there is a closed jira support request SERVER-4798 regarding multiple pop operations, but in comment they have suggested to use update with aggregation pipeline option.
So you can try update with aggregation pipeline starting from MongoDB 4.2,
$slice, pass negative number and it will slice elements from 0 index
let n = 2;
db.collection.updateOne(
{}, // your query
[{
$set: { arr: { $slice: ["$arr", -n] } }
}]
)
Playground
What #turivishal metioned is true however it only works if array's size is always 4. For it to work for all array sizes we should consider size of the array in aggregation, so:
let n = 2;
db.collection.update({},
[
{
$set: {
arr: {
$slice: [
"$arr",
{
$subtract: [
-n,
{
$size: "$arr"
}
]
},
]
}
}
}
])
Playground

Search for multiple documents in mongodb

In mongodb, is there a way I can search for multiple items at once? For example, I have a Products collection. I want to return an array of objects products where product_code = 1000, 2000. 3000.
My semi-pseudocode query would be something like:
Products.find({product_code: [1000, 2000, 3000]});
The desired output would be something like:
[
{
"_id":"1",
"product_code":"1000",
"price":"300"
},
{
"_id":"2",
"product_code":"2000",
"price":"500"
},
{
"_id":"3",
"product_code":"3000",
"price":"400"
}
]
I couldn't find anything relating to this in the documentation...
You can use the $in operator to find documents where a field contains any value in the array:
Products.find({product_code: {$in: ['1000', '2000', '3000']}});

MongoDB: distinct tuples

Suppose to have a collection of MongoDB documents with the following structure:
{
id_str: "some_value",
text: "some_text",
some_field: "some_other_value"
}
I would like to filter such documents so as to obtain the ones with distinct text values.
I learned from the MongoDB documentation how to extract unique field values from a collection, using the distinct operation. Thus, by performing the following query:
db.myCollection.distinct("text")
I would obtain an array containing the distinct text values:
["first_distinct_text", "second_distinct_text",...]
However, this is not the result that i would like to obtain. Instead, I would like to have the following:
{ "id_str": "a_sample_of_id_having_first_distinct_text",
"text": "first_distinct_text"}
{ "id_str": "a_sample_of_id_having_second_distinct_text",
"text": "second_distinct_text"}
I am not sure if this can be done with a single query.
I found a similar question which, however, do not solve fully my problem.
Do you have any hint on how to solve this problem?
Thanks.
You should look into making an aggregate query using the $group stage, and probably using the $first operator.
Maybe something along the lines of:
db.myCollection.aggregate([{ $group : { _id : { text: "$text"},
text: { $first: "$id_str" }
}
}])
try:
db.myCollection.aggregate({$group: {_id: {'text': "$text", 'id_str': '$id_str'}}})
More information here: http://docs.mongodb.org/manual/reference/method/db.collection.aggregate/

Sorting in MongoDB by elemMatch

Is there a way of sorting in MongoDB based on an $elemMatch? For example, I have documents which look like this:
{
'user': ObjectId('fsdfsdf'),
...
'array_of_things': [
{
'attribute_1': ObjectId('sdfsdfsd'),
'attribute_2': ObjectId('sdfsfsdf'),
'value': 30000
},
{
'attribute_1': ObjectId('dfdfgfdg'),
'attribute_2': ObjectId('gdfgdfgd'),
'value': 100
},
{
'attribute_1': ObjectId('mbnmbbmb'),
'attribute_2': ObjectId('mbnmbnmb'),
'value': 2000
},
...
]
}
I need to be able to query this data based on a matching element inside the array_of_things field (which is simple enough with an $elemMatch). The problem arises because I also need to be able to sort by value (ascending or descending) that match a certain attribute. For example, a query might be:
{
'user': ObjectId('fsdfsdf'),
'array_of_things': {
$elemMatch: {
'attribute_1': ObjectId('dfdfgfdg'),
'value': {
$gt: 1
}
}
}
}
Sorting solely on value (e.g. sort({ 'array_of_things.value': -1 }) predictably only sorts on all values in any array element, not matching attribute_1 first.
Is there a way to do this?
Apologies if this is an already-asked question, but I can't seem to find any solution to it after looking.
This is currently not possible with the standard query language. You can achieve it with the aggregation framework at (potentially) some performance penalty.

remove documents with array field's size less than 3 in mongoDB

i have a mongoDB collection named col that has documents that look like this
{
{
intField:123,
strField:'hi',
arrField:[1,2,3]
},
{
intField:12,
strField:'hello',
arrField:[1,2,3,4]
},
{
intField:125,
strField:'hell',
arrField:[1]
}
}
Now i want to remove documents from collection col in which size of the array field is less than 2.
So i wrote a query that looks like this
db.col.remove({'arrField':{"$size":{"$lt":2}}})
Now this query doesnt do anything. i checked with db.col.find() and it returns all the documents. Whats wrong with this query?
With MongoDB 2.2+ you can use numeric indexes in condition object keys to do this:
db.col.remove({'arrField.2': {$exists: 0}})
This will remove any document that doesn't have at least 3 elements in arrField.
From the documentation for $size:
You cannot use $size to find a range of sizes (for example: arrays with more than 1 element).
The docs recommend maintaining a separate size field (so in this case, arrFieldSize) with the count of the items in the array if you want to try this sort of thing.
Note that for some queries, it may be feasible to just list all the counts you want in or excluded using (n)or conditions.
In your example, the following query will give all documents with less than 2 array entries:
db.col.find({
"$or": [
{ "arrField": {"$exists" => false} },
{ "arrField": {"$size" => 1} },
{ "arrField": {"$size" => 0} }
]
})
The following should work
db.col.remove({$where: "this.arrField.length < 2"})