List all values of a certain field in mongodb - 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.

Related

how are two values of different BSON types compared?

I'm reading MongoDB BSON Comparison docs.
But I couldn't understand clearly.
When comparing values of different BSON types, MongoDB uses the following comparison order, from lowest to highest:
MinKey (internal type)
Null
Numbers (ints, longs, doubles, decimals)
Symbol, String
...
Is there any implicit type conversion and how it works?
Could you give me a few examples?
There is no type conversion.
When two items are compared:
If they have different types, the order of the types referenced becomes the order of the items.
If they have the same type, the respective values are compared, and their order becomes the order of the items.
Try:
> db.foo.insertMany([{a:1},{a:[]},{a:'1'},{a:{}},{a:true},{a:false},{a:/test/},{a:null},{a:[1]}])
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("5e8aeae7d11542e71728da71"),
ObjectId("5e8aeae7d11542e71728da72"),
ObjectId("5e8aeae7d11542e71728da73"),
ObjectId("5e8aeae7d11542e71728da74"),
ObjectId("5e8aeae7d11542e71728da75"),
ObjectId("5e8aeae7d11542e71728da76"),
ObjectId("5e8aeae7d11542e71728da77"),
ObjectId("5e8aeae7d11542e71728da78"),
ObjectId("5e8aeae7d11542e71728da79")
]
}
> db.foo.find().sort({a: 1})
{ "_id" : ObjectId("5e8aeae7d11542e71728da72"), "a" : [ ] }
{ "_id" : ObjectId("5e8aeae7d11542e71728da78"), "a" : null }
{ "_id" : ObjectId("5e8aeae7d11542e71728da71"), "a" : 1 }
{ "_id" : ObjectId("5e8aeae7d11542e71728da79"), "a" : [ 1 ] }
{ "_id" : ObjectId("5e8aeae7d11542e71728da73"), "a" : "1" }
{ "_id" : ObjectId("5e8aeae7d11542e71728da74"), "a" : { } }
{ "_id" : ObjectId("5e8aeae7d11542e71728da76"), "a" : false }
{ "_id" : ObjectId("5e8aeae7d11542e71728da75"), "a" : true }
{ "_id" : ObjectId("5e8aeae7d11542e71728da77"), "a" : /test/ }
>
The behavior of the empty array does not seem to match the documentation.

Insert new fields to document at given array index in MongoDB

I have the following document structure in a MongoDB collection :
{
"A" : [ {
"B" : [ { ... } ]
} ]
}
I'd like to update this to :
{
"A" : [ {
"B" : [ { ... } ],
"x" : [],
"y" : { ... }
} ]
}
In other words, I want the "x" and "y" fields to be added to the first element of the "A" array without loosing "B".
Ok as there is only one object in A array you could simply do as below :
Sample Collection Data :
{
"_id" : ObjectId("5e7c3cadc16b5679b4aeec26"),
A:[
{
B: [{ abc: 1 }]
}
]
}
Query :
/** Insert new fields into 'A' array's first object by index 0 */
db.collection.updateOne(
{ "_id" : ObjectId("5e7c3f77c16b5679b4af4caf") },
{ $set: { "A.0.x": [] , "A.0.y" : {abcInY :1 }} }
)
Output :
{
"_id" : ObjectId("5e7c3cadc16b5679b4aeec26"),
"A" : [
{
"B" : [
{
"abc" : 1
}
],
"x" : [],
"y" : {
"abcInY" : 1.0
}
}
]
}
Or Using positional operator $ :
db.collection.updateOne(
{ _id: ObjectId("5e7c3cadc16b5679b4aeec26") , 'A': {$exists : true}},
{ $set: { "A.$.x": [] , "A.$.y" : {abcInY :1 }} }
)
Note : Result will be the same, but functionally when positional operator is used fields x & y are inserted to first object of A array only when A field exists in that documents, if not this positional query would not insert anything (Optionally you can check A is an array condition as well if needed). But when you do updates using index 0 as like in first query if A doesn't exist in document then update would create an A field which is an object & insert fields inside it (Which might cause data inconsistency across docs with two types of A field) - Check below result of 1st query when A doesn't exists.
{
"_id" : ObjectId("5e7c3f77c16b5679b4af4caf"),
"noA" : 1,
"A" : {
"0" : {
"x" : [],
"y" : {
"abcInY" : 1.0
}
}
}
}
However, I think I was able to get anothe#whoami Thanks for the suggestion, I think your first solution should work. However, I think I was able to get another solution to this though I'm not sure if its better or worse (performance wise?) than what you have here. My solution is:
db.coll.update( { "_id" : ObjectId("5e7c4eb3a74cce7fd94a3fe7") }, [ { "$addFields" : { "A" : { "x" : [ 1, 2, 3 ], "y" : { "abc" } } } } ] )
The issue with this is that if "A" has more than one array entry then this will update all elements under "A" which is not something I want. Just out of curiosity is there a way of limiting this solution to only the first entry in "A"?

MongoDB Finding nested object value

I'm trying to find documents within my collection that have a numeric value greater than x amount. The documentation explains how to do this for top level values however I'm struggling to retrieve the correct data for values that are within child objects.
Sample JSON
{
"_id" : ObjectId("5c32646c9f3315c3e8300673"),
"key" : "20190107",
"__v" : 0,
"chart" : [
{
"_id" : ObjectId("5c3372e5c35e924984f28e03"),
"volume" : "0",
"close" : "47.24",
"time" : "09:30 AM"
},
{
"_id" : ObjectId("5c3372e5c35e924984f28d34"),
"volume" : "50",
"close" : "44.24",
"time" : "09:50 AM"
}
]
}
I want to retrieve volumes greater than 10. I've tried
db.symbols.find({"chart.volume": { $gt: 10 } } )
db.symbols.find({"volume": { $gt: 10 } } )
Any help appreciated.
Your sample JSON has string values for the chart.volume field. If it was numeric, then your first solution:
db.symbols.find({"chart.volume": { $gt: 10 } } )
would work fine. The docs do explain how to do this.

mongodb $elemMatch in query return all sub docs

db.aaa.insert({"_id":1, "m":[{"_id":1,"a":1},{"_id":2,"a":2}]})
db.aaa.find({"_id":1,"m":{$elemMatch:{"_id":1}}})
{ "_id" : 1, "m" : [ { "_id" : 1, "a" : 1 }, { "_id" : 2, "a" : 2 } ] }
Using $elemMatch as query operator, it return all sub docs in 'm' !! Strange!
Use it as project operator:
db.aaa.find({"_id":1},{"m":{$elemMatch:{"_id":1}}})
{ "_id" : 1, "m" : [ { "_id" : 1, "a" : 1 } ] }
This is OK. Following this logic, use it as query operator in update will change all sub docs in 'm'. So I do:
db.aaa.update({"_id":1,"m":{$elemMatch:{"_id":1}}},{$set:{"m.$.a":3}})
db.aaa.find()
{ "_id" : 1, "m" : [ { "_id" : 1, "a" : 3 }, { "_id" : 2, "a" : 2 } ] }
It works in manner of as second example(project operator). This really confuse me.
Give me a explain
It Isn't strange, it's how it works.
You are using $elemMatch to match an element within an array contained in your document. That means it mactches the "document" and not the "array element", so it does not just selectively display only the array element that was matched.
What you can do, and how you used it in with the $set operator, is use a positional $ operator to indicate the matched "position" from your query side:
db.aaa.find({"_id":1},{"m":{$elemMatch:{"_id":1}}},{ "m.$": 1 })
And that will show you only one element of the array. But it is of course *still an array in the result shown, and you cannot cast it to a different type.
The other part of the usage is that this will only match once. And only the first match will be assigned to the positional operator.
So perhaps the most succinct explaination is you matching the "document that contains" the properties of the sub-document your specified in your query, and not just the "sub-document" itself.
See the documentation for more:
http://docs.mongodb.org/manual/reference/operator/projection/positional/
http://docs.mongodb.org/manual/reference/operator/query/elemMatch/

Return range of documents around ID in MongoDB

I have an ID of a document and need to return the document plus the 10 documents that come before and the 10 documents after it. 21 docs total.
I do not have a start or end value from any key. Only the limit in either direction.
Best way to do this? Thank you in advance.
Did you know that ObjectID's contain a timestamp? And that therefore they always represent the natural insertion order. So if you are looking for documents before an after a known document _id you can do this:
Our documents:
{ "_id" : ObjectId("5307f2d80f936e03d1a1d1c8"), "a" : 1 }
{ "_id" : ObjectId("5307f2db0f936e03d1a1d1c9"), "b" : 1 }
{ "_id" : ObjectId("5307f2de0f936e03d1a1d1ca"), "c" : 1 }
{ "_id" : ObjectId("5307f2e20f936e03d1a1d1cb"), "d" : 1 }
{ "_id" : ObjectId("5307f2e50f936e03d1a1d1cc"), "e" : 1 }
{ "_id" : ObjectId("5307f2e90f936e03d1a1d1cd"), "f" : 1 }
{ "_id" : ObjectId("5307f2ec0f936e03d1a1d1ce"), "g" : 1 }
{ "_id" : ObjectId("5307f2ee0f936e03d1a1d1cf"), "h" : 1 }
{ "_id" : ObjectId("5307f2f10f936e03d1a1d1d0"), "i" : 1 }
{ "_id" : ObjectId("5307f2f50f936e03d1a1d1d1"), "j" : 1 }
{ "_id" : ObjectId("5307f3020f936e03d1a1d1d2"), "j" : 1 }
So we know the _id of "f", get it and the next 2 documents:
> db.items.find({ _id: {$gte: ObjectId("5307f2e90f936e03d1a1d1cd") } }).limit(3)
{ "_id" : ObjectId("5307f2e90f936e03d1a1d1cd"), "f" : 1 }
{ "_id" : ObjectId("5307f2ec0f936e03d1a1d1ce"), "g" : 1 }
{ "_id" : ObjectId("5307f2ee0f936e03d1a1d1cf"), "h" : 1 }
And do the same in reverse:
> db.items.find({ _id: {$lte: ObjectId("5307f2e90f936e03d1a1d1cd") } })
.sort({ _id: -1 }).limit(3)
{ "_id" : ObjectId("5307f2e90f936e03d1a1d1cd"), "f" : 1 }
{ "_id" : ObjectId("5307f2e50f936e03d1a1d1cc"), "e" : 1 }
{ "_id" : ObjectId("5307f2e20f936e03d1a1d1cb"), "d" : 1 }
And that's a much better approach than scanning a collection.
Neil's answer is a good answer to the question as stated (assuming that you are using automatically generated ObjectIds), but keep in mind that there's some subtlety around the concept of the 10 documents before and after a given document.
The complete format for an ObjectId is documented here. Note that it consists of the following fields:
timestamp to 1-second resolution,
machine identifier
process id
counter
Generally if you don't specify your own _ids they are automatically generated by the driver on the client machine. So as long as the ObjectIds are generated on a single process on a client single machine, their order does indeed reflect the order in which they were generated, which in a typical application will also be the insertion order (but need not be). However if you have multiple processes or multiple client machines, the order of the ObjectIds for objects generated within a given second by those multiple sources has an unpredictable relationship to the insertion order.