I have a collection of documents in which a field name appears to have a dot:
{
"prod_id": "123",
"prod_cost (whole)": 49
"prod_cost (dec.)": 49
}
How can I effectively run an aggregation pipeline using that field?
As of now, it reports null values since it considers ")" as an additional nested field for prod_cost (dec.).
From MongoDB version 5,
MongoDB 5.0 adds improved support for the use of ($) and (.) in field names. There are some restrictions. See Field Name Considerations for more details.
Field Names with Periods (.) and Dollar Signs ($)
In most cases data that has been stored using field names like these is not directly accessible. You need to use helper methods like $getField, $setField, and $literal in queries that access those fields.
{ "$getField": "prod_cost (dec.)" }
Sample MongoPlayground
To access field in object, you can refer to Query a Field in a Sub-document demo.
{
"$getField": {
field: {
$literal: "prod_cost (dec.)"
},
input: "$productInfo"
}
}
Sample Mongo Playground (Nested object)
Related
I have to make a consult on a data base in Mongodb, but usin colab (google colab), i found that the existing documentation (oficial and every other site) have a similar way of doing the consult but not de same (in colab with "less tan" operator yo have to do "$lt" and $lt doesn't work) thas why i am here asking how can i translate a group by and sum consult.
For more detail i want to group by name of publisher and sum another field (weeks on best seller)
Query = collection.aggregate(
[
{'$group':{'_id': 'publisher', 'Cantidad_total': { "$sum": 'weeks_on_list' }}}])
for elemento in Query:
pprint.pprint(elemento)
this is what i came up with (that doesn´t fail) but give this
{'Cantidad_total': 0, '_id': 'publisher'}
You just need a couple of $.
From the docs:
Expressions:
Expressions can include field paths , literals , system variables ,
expression objects , and expression operators . Expressions can be
nested.
Field Paths:
Aggregation expressions use field path to access fields in the input
documents. To specify a field path, prefix the field name or the
dotted field name (if the field is in the embedded document) with a
dollar sign $. For example, "$user" to specify the field path for the
user field or "$user.name" to specify the field path to "user.name"
field.
So for your particular example, you want your aggregation pipeline to be:
[
{
"$group": {
"_id": "$publisher",
"Cantidad_total": {
"$sum": "$weeks_on_list"
}
}
}
]
I have a MongoDB Collection that contains documents with a nested map, similar to the following document:
{
"_id": "1"
"accounts": {
"account-id-1": { "email": "example1#example.com", ... },
"account-id-2": { "email": "example2#example.com", ... },
}
}
The accounts map contains account IDs as keys and the remaining account data as values/objects. Now I want to add an index for the email field of the nested object, but I can't do that by defining the fields as one would normally do for nested fields, e.g. accounts.account-id-1.email because the mid part (account-id-1) is different for each entry.
I have read about wildcard indexes, but it seems to me that the index expression always ends withe the special wildcard symbol $**, but never has it in the middle.
My question is whether it's possible to define such an index in the following way or similarly: accounts.$**.email, so that only the email field gets indexed.
I have a database with 15,574,934 records in mongo
I want to rename some columns to:
db.offerPhotos.files.update({}, {$rename: { 'orgFilename': 'metadata.orgFilename', 'offerId': 'metadata.offerId', 'batch': 'metadata.batch', 'group': 'metadata.group', 'size': 'metadata.size', 'mimeType': 'metadata.mimeType'}}, false, true)
I do it by mongo CLI but I'm waiting and waiting and nothing happens
How to do it better?
As per MongDB naming conventions
Field names cannot contain the null character.
Top-level field names cannot start with the dollar sign ($) character.
The use of $ and . in field names is not recommended and is not supported by the official MongoDB drivers
Otherwise, starting in MongoDB 3.6, the server permits storage of
field names that contain dots (i.e. .) and dollar signs (i.e. $).
Reason for the slowness:
The $rename operator logically performs an $unset of both the old name and the new name, and then performs a $set operation with the new name.
It does two operation first on a document unset on old and new name. Then it performs set operation. So totally three operations per document.
Reference
And you are actually doing more worse. Because you are converting a field to nested one.
Input doc:
{
"_id":"",
"key":1
}
Rename:
db.test.update({}, {
"$rename": {
"key": "key1.name"
}
})
Output:
/* 1 */
{
"_id" : ObjectId("5ef718a290c7f76c305aa21c"),
"key1" : {
"name" : 1
}
}
It's converted to nested one. You are doing worse because each rename results in 3 operations on a nested doc which in turn contains many fields.
Approximately you are doing 1.6million * 3 * 6 operations on a doc. Hence it is slow.
how to print field and length of this field
e.g. I have {name:"aaa"} document is collection "names"
then the expected output is
{name:"aaa", name_legth:3}
Please help.
MongoDB versions <3.2 don't have a text aggregation operator to compute length of a string value stored in a field. If you are using version 3.2 or older, you will need to implement the length computation outside the DB (such as in the controller layer of an MVC architecture).
Version 3.4, though, includes several new and useful aggregation operators including the $strLenCP operator which should serve your purpose. The usage for your case would be as follows:
db.names.aggregate(
[
{
$project: {
"name": 1,
"name_length": { $strLenCP: "$name" }
}
}
]
)
The documentation for the aggregation operator can be found here.
I needed some help to create a count query on nested objects in a field, across all documents. Each document json has a many fields. One particular field called "hotlinks" comprises of many internal dynamic object fields.
Doc1:
{
hotlinks : { 112222:{....} , 333333: {.....} , 545555: {.....} }
}
Doc2:
{
hotlinks : { 67756:{....} , 756767: {.....} , 1111111: {.....} }
}
Each document has a hotlinks fields. The hotlinks field comprises of varied inner hotlink objects. Each key is a java unique id and has objects that contain data (inner fields).
I needed a way to get the count of all the inner nested objects of the field – ‘hotlinks’.
For example the summation of inner objects of hotlinks in doc1 and doc2 would be 6.
Is there any way to do this via a single query to get the count across all documents.
Thanks a lot,
Karan
Quite possible if using MongoDB 3.6 and newer though the aggregation framework.
Use the $objectToArray operator within an aggregation pipeline to convert the document to an array. The return array contains an element for each field/value pair in the original document. Each element in the return array is a document that contains two fields k and v.
On getting the array, you can then leverage the use of the $size operator which returns the number of elements in the given array thus giving you the count per document.
Getting the count across all the documents requires a $group pipeline where you specify the _id key of null or a constant value which gives calculates accumulated values for all the input documents as a whole.
All this can be done in a single pipeline by nesting the expressions as follows:
db.collection.aggregate([
{ "$group": {
"_id": null,
"count": {
"$sum": {
"$size": { "$objectToArray": "$hotlinks" }
}
}
} }
])
Example Output
{
"_id" : null,
"count" : 6
}
this may not be the best approach, but you can define a javascript variable and sum up the counts. i.e;
var hotlinkTotal=0;
db.collection.find().forEach(function(x){hotlinkTotal+=x.hotlinks.length;});
print(hotlinkTotal);