Pymongo $size operator - mongodb

Is $size equivalent operator for query condition in pymongo?
like
{'a': {'$size': 3}}
for {a: [1,2,3]}

I don't quite understand your question, but if you're asking if db.foo.find({a: {$size: 3}}) would return the document {a: [1, 2, 3]}, then the answer is yes.

Related

Mongo remove document if all elements in array match condition

Docs:
{
_id: 1,
items: [{thing: 5}, {thing: 7}]
}
{
_id: 2,
items: [{thing: 5}, {thing: 11}]
}
I would like to remove all docs from the collection above if all elements in array have "thing" < 10. IE for that case doc 1 should be removed, doc 2 should remain.
Is it possible with a query to find only docs where all elements in the array match with a $lt query?
I tried this:
db.mycollection.remove({items: {$all: [{$elemMatch: {thing: {$lt: 11}}}]}})
However that will remove all docs if any of the elements in the array match the condition.
Use double negative (De-Morgan law):
{items: {$not: {$elemMatch: {thing: {$gte: 11}}}}}

How to create index to process $in queries sorted by another field?

Is there any way to create index to process queries like
db.col.find({a: {$in: [1, 2, 3]}).sort({b: 1})
or
db.col.find({a: {$in: [1, 2, 3]}).sort({b: 1}).limit(N)
effectively?
It's said here that index {a: 1, b: 1} should be used with SORT_MERGE for such queries but it doesn't, explain() gives me regular SORT only. This index is used only if I have query like db.col.find({a: 1}).sort({b: 1}) or db.col.find({a: {$in: [1]}).sort({b: 1}) (with only one $in element).
hint({a:1, b:1}) also did not help.
Upd. Mongodb 3.2.1

Mongodb: find subdocuments whose fields are in non-canonical order

As I switch to subdoc equality testing, I want to ensure all of my documents' subdocs field orders are in the canonical ordering which I will be testing. I cannot figure out a good query for checking this.
That is, given these records:
{'_id': .., 'doc':{'a': 1, 'b': 2}, ..}
{'_id': .., 'doc':{'a': 11, 'b': 21}, ..}
{'_id': .., 'doc':{'a': 0, 'b': 2}, ..}
...
{'_id': .., 'doc':{'b': 0, 'a': 4}, ..}
If I query with 'doc' : {'a': 4, 'b': 0} I won't find the doc w/ keys in the "wrong" order. I'd like to write a one-time query to find all of these docs, but even with $where I don't see how I can check the order of keys (I guess the where could try querying with the canonical order if need be).
So, I wrote a $where which does it. I'm not sure it's the best solution:
db.mycollection.find({$where: function() {
var keys = Object.keys(this['doc']);
var ref = ['a', 'b'];
for (var i=0; i < ref.length; i++) {
if (keys[i] != ref[i]) return true;
}
return false;
}},
{_id: 1})
Obviously this is overkill if my docs really only had the 2 subfields, but that's the pattern.

Remove fields from elements of inner array in MongoDB

Say I have:
db.test.insert({foos: [{bars: [{}, {}]}]});
db.test.insert({foos: [{bars: [{}, {}]}]});
Now I want to remove all bars-fields of all foos. How do I do that?
db.test.update({}, {$unset: {"foos.bars": 1}});
and
db.test.update({}, {$pull: {"foos.bars": {}}});
doesn't do anything.
db.test.update({}, {$pull: {"foos.$.bars": {}}});
gives error:
"Cannot apply the positional operator without a corresponding query field containing an array."
Any help highly appreciated.
Adding an exist-query on the subdocument in the array seemed to do the trick:
db.test.remove();
db.test.insert({foos: [{bars: [{"baz": 1} ]}]});
db.test.insert({foos: [{bars: [{"baz": 1} ]}]});
db.test.find({'foos.bars': {$exists: true}}).count();
db.test.update({'foos.bars': {$exists: true}}, {$unset: {'foos.$.bars': 1}}, false, true);
db.test.find({'foos.bars': {$exists: true}}).count();

Mongo aggregation with $ne

I can't seem to find any resources at all on Mongo aggregation with the boolean operations. My query looks something like this (I am using the pymongo driver):
db.collection.aggregate([{'$match': {'foo': 3, 'bar': 'baz'}},
{'$project': {'quxx': 1, '_id': 0, 'count': 1}},
{'$group': {'total': {'$sum': '$count'}, '_id': '$quxx'}},
{'$sort': {'total': -1}},
{'$limit': 2000}])
Which all works great ($match is on an index etc). Now, there is a single rogue quxx that I would like to filter out of the pipeline so I thought that I would use the $ne operator. However, I can't seem to figure out the proper way to do it! I'm not sure if I'm not placing it at the right point (I want it after the $match operator but before the $group operator) or I have the syntax wrong but help would be appreciated.
The things I have tried so far (all in their own step after $match) are:
{'$quxx': {'$ne': 'rogue'}}
{'quxx': {'$ne': 'rogue'}}
{'$ne': {'quxx': 'rogue'}}
{'$ne': {'$quxx': 'rogue'}}
Every single one of them gives me unrecognized pipeline op.
You would either put that in its own $match pipeline element, or just include it in the initial $match.
So either add:
{'$match': {'quxx': {'$ne': 'rogue'}}}
or modify the initial $match to:
{'$match': {'foo': 3, 'bar': 'baz', 'quxx': {'$ne': 'rogue'}}}