MongoDB Remove All Rows with a Certain Field - mongodb

How can I remove all rows/records/entries that have a certain property set in MongoDB? For example, how can I remove all the rows that have an x field without removing the last row, which has no x field?
{ "_id" : ObjectId("53907a0adf55a0a97263b36d"), "x" : 21 }
{ "_id" : ObjectId("53907a0adf55a0a97263b36e"), "x" : 22 }
{ "_id" : ObjectId("53907a0adf55a0a97263b36f"), "x" : 23 }
{ "_id" : ObjectId("53907a0adf55a0a97263b370"), "x" : 24 }
{ "_id" : ObjectId("53907a16df55a0a97263b372"), "name" : "Bob" }
I tried this, but it removed everything:
db.testData.remove({}, {x:""})

http://docs.mongodb.org/manual/reference/operator/query/exists/
db.testData.remove({x: {$exists: true}})

Related

Positional operator and field limitation

In a find query projection, fields I specify after the positional operator are ignored and the whole document is always returned.
'myArray.$.myField' : 1 behave exactly like 'myArray.$' : 1
the positional operator selects the right document. But this document is quite big. I would like to project only 1 field from it.
Exemple:
db.getCollection('match').find({"participantsData.id" : 0001}, { 'participantsData.$.id': 1, })
here the response I have
{
"_id" : "myid",
"matchCreation" : 1463916465614,
"participantsData" : [
{
"id" : 0001,
"plenty" : "of",
"other" : "fields",
"and" : "subdocuments..."
}
]
}
This is what I want
{
"_id" : "myid",
"matchCreation" : 1463916465614,
"participantsData" : [
{
"id" : 0001
}
]
}
Is it possible with mongo?
Yes it can be done in mongo
Please try the below query
db.getCollection('match').find(
{"participantsData.id" : 0001},
{"participantsData.id": 1, "matchCreation": 1 })
This will give you the below result
{
"_id" : "myid",
"matchCreation" : 1463916465614,
"participantsData" : [
{
"id" : 1
}
]
}

Mongo DB find method confusion in Implicit AND

I am new to mongodb I have started to learn basic syntax recently. I was trying operators with find method, and I got a confusing case while trying Implicit AND.
My Collection mathtable having 400 documents is as follows:
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4b2") , "index" : 1 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4b3") , "index" : 2 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4b4") , "index" : 3 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4b5") , "index" : 4 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4b6") , "index" : 5 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4b7") , "index" : 6 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4b8") , "index" : 7 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4b9") , "index" : 8 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4ba") , "index" : 9 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4bb") , "index" : 10 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4bc") , "index" : 11 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4bd") , "index" : 12 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4be") , "index" : 13 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4bf") , "index" : 14 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4c0") , "index" : 15 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4c1") , "index" : 16 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4c2") , "index" : 17 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4c3") , "index" : 18 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4c4") , "index" : 19 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4c5") , "index" : 20 }
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4d1") , "index" : 1 }
..
..
{ "_id" : ObjectId("540efc2bd8af78d9b0f5d4z5") , "index" : 20 }
There are 400 rows in mathtable collection:
Value of index ranges from 1 to 20.
For each value of index there are 20 entries with different _id value.
I am trying below two operations and expecting same results, considering that they are both implicit AND cases.
Calculating even index values having a value greater than 5.
Using classic EXPLICIT AND ( results into 160 records ) :
db.mathtable.count({
$and: [
{ index: { $mod: [2,0] } },
{ index: { $gt: 5 } }
]
});
Using variable name only once ( results into 160 records ) :
db.mathtable.count({
index : { $mod : [2,0] , $gt:5 }
});
Using field name with every condition ( results into 300 records ):
db.mathtable.find({
index : { $mod : [2,0]} ,
index : {$gt:5}
});
Using field name with every condition, conditions in opposite order ( results into 200 records ):
db.mathtable.find({
index : {$gt:5} ,
index : { $mod : [2,0]}
});
There is no mention of implicit OR in mongoDB documentation( or at-least I did not find a direct reference like implicit AND ) .
I was expecting same count of records ( 160 ) in both cases. I am unable to understand why above codes are behaving differently.
Also, order of condition specification results into different number of results. As per observation, only the last condition specified in find was applied, when same field was specified multiple times. That is weird and incorrect.
NOTE: I am using Mongo-DB-2.6 and code is being executed on mongo shell that comes with the distribution.
Json or an associative array or a map does not contain duplicate keys:
db.mathtable.find({
index : { $mod : [2,0]} ,
index : {$gt:5}
});
The above will be considered equivalent to:
db.mathtable.find({
index : {$gt:5}
});
The first condition will be overwritten,
and the below,
db.mathtable.find({
index : {$gt:5} ,
index : { $mod : [2,0]}
});
will be equivalent to,
db.mathtable.find({
index : { $mod : [2,0]}
});
However in the first case,
db.mathtable.count({
$and: [
{ index: { $mod: [2,0] } },
{ index: { $gt: 5 } }
]
});
the $and takes two json documents as input and behaves as expected.
and in the second case, count takes a single document with no duplicate keys and behaves as expected.
db.mathtable.count({
index : { $mod : [2,0] , $gt:5 }
});
Hence the difference in the number of rows returned. Hope it is helpful.

List all values of a certain field in mongodb

How would I get an array containing all values of a certain field for all of my documents in a collection?
db.collection:
{ "_id" : ObjectId("51a7dc7b2cacf40b79990be6"), "x" : 1 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990be7"), "x" : 2 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990be8"), "x" : 3 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990be9"), "x" : 4 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990bea"), "x" : 5 }
"db.collection.ListAllValuesForfield(x)"
Result: [1,2,3,4,5]
Also, what if this field was an array?
{ "_id" : ObjectId("51a7dc7b2cacf40b79990be6"), "y" : [1,2] }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990be7"), "y" : [3,4] }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990be8"), "y" : [5,6] }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990be9"), "y" : [1,2] }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990bea"), "y" : [3,4] }
"db.collection.ListAllValuesInArrayField(y)"
Result: [1,2,3,4,5,6,1,2,3,4]
Additionally, can I make this array unique? [1,2,3,4,5,6]
db.collection.distinct('x')
should give you an array of unique values for that field.
Notice: My answer is a fork from the original answer.
Before any "thumbs up" here, "thumbs up" the accepted answer :).
db.collection.distinct("NameOfTheField")
Finds the distinct values for a specified field across a single collection or view and returns the results in an array.
Reference: https://docs.mongodb.com/manual/reference/method/db.collection.distinct/
This would return an array of docs, containing just it's x value...
db.collection.find(
{ },
{ x: 1, y: 0, _id:0 }
)
db.collection_name.distinct("key/field_name") - This will return a list of distinct values in the key name from the entire dictionary.
Just make sure you don't use the curly brackets after round brackets.

Mongodb Map/Reduce - Multiple Group By

I am trying to run a map/reduce function in mongodb where I group by 3 different fields contained in objects in my collection. I can get the map/reduce function to run, but all the emitted fields run together in the output collection. I'm not sure this is normal or not, but outputting the data for analysis takes more work to clean up. Is there a way to separate them, then use mongoexport?
Let me show you what I mean:
The fields I am trying to group by are the day, user ID (or uid) and destination.
I run these functions:
map = function() {
day = (this.created_at.getFullYear() + "-" + (this.created_at.getMonth()+1) + "-" + this.created_at.getDate());
emit({day: day, uid: this.uid, destination: this.destination}, {count:1});
}
/* Reduce Function */
reduce = function(key, values) {
var count = 0;
values.forEach(function(v) {
count += v['count'];
}
);
return {count: count};
}
/* Output Function */
db.events.mapReduce(map, reduce, {query: {destination: {$ne:null}}, out: "TMP"});
The output looks like this:
{ "_id" : { "day" : "2012-4-9", "uid" : "1234456", "destination" : "Home" }, "value" : { "count" : 1 } }
{ "_id" : { "day" : "2012-4-9", "uid" : "2345678", "destination" : "Home" }, "value" : { "count" : 1 } }
{ "_id" : { "day" : "2012-4-9", "uid" : "3456789", "destination" : "Login" }, "value" : { "count" : 1 } }
{ "_id" : { "day" : "2012-4-9", "uid" : "4567890", "destination" : "Contact" }, "value" : { "count" : 1 } }
{ "_id" : { "day" : "2012-4-9", "uid" : "5678901", "destination" : "Help" }, "value" : { "count" : 1 } }
When I attempt to use mongoexport, I can not separate day, uid, or destination by columns because the map combines the fields together.
What I would like to have would look like this:
{ { "day" : "2012-4-9" }, { "uid" : "1234456" }, { "destination" : "Home"}, { "count" : 1 } }
Is this even possible?
As an aside - I was able to make the output work by applying sed to the file and cleaning up the CSV. More work, but it worked. It would be ideal if I could get it out of mongodb in the correct format.
MapReduce only returns documents of the form {_id:some_id, value:some_value}
see: How to change the structure of MongoDB's map-reduce results?

Mongo DB : Impact of object schema changes on document design

How do you handle schema changes in Mongo db e.g. say after refactoring you change your object schema design and that impacts the document schema. Is there a way to update the document schema?
You can run an update on the entire schema, removing fields, or adding fields and setting them to calculated values, if that's what you're getting at.
Say you had an x field, and you want to add a y field that should be set to x/2, you could do something like this:
PRIMARY> db.test.insert({x:15});
PRIMARY> db.test.insert({x:30});
PRIMARY> db.test.insert({x:50});
PRIMARY> db.test.find();
{ "_id" : ObjectId("4f9df1ebed2b924eedb8cad9"), "x" : 15 }
{ "_id" : ObjectId("4f9df1eeed2b924eedb8cada"), "x" : 30 }
{ "_id" : ObjectId("4f9df1f1ed2b924eedb8cadb"), "x" : 50 }
PRIMARY> db.test.find().forEach(function(doc) {
doc.y = doc.x/2;
db.test.save(doc);
});
PRIMARY> db.test.find();
{ "_id" : ObjectId("4f9df1ebed2b924eedb8cad9"), "x" : 15, "y" : 7.5 }
{ "_id" : ObjectId("4f9df1eeed2b924eedb8cada"), "x" : 30, "y" : 15 }
{ "_id" : ObjectId("4f9df1f1ed2b924eedb8cadb"), "x" : 50, "y" : 25 }