Using multiply aggregation with MongoDB - mongodb

I have several documents that looks like this:
{
"hostname" : "server1.example.com",
"virtual" : true,
"processors" : {
"cores" : 1,
"sockets" : 4
}
}
{
"hostname" : "server2.example.com",
"virtual" : false,
"processors" : {
"cores" : 2,
"sockets" : 2
}
}
I am trying to output the hostname, virtual and total number of cores for each document. I keep getting a syntax error that has me stumped. Here is my query and the syntax error.
c.aggregate( {
$project: {
hostname: 1,
total-cores: {$multiply: ["$processors.sockets", "$processors.cores"]},
virtual: 1,
_id: 0
}
});
Thu Apr 25 14:12:18 SyntaxError: missing : after property id (shell):1
Judging from the documentation, this should work. What am I missing? I am running MongoDB 2.2.2.
http://docs.mongodb.org/manual/reference/aggregation/project/

Quote the total-cores key so that it's parsed correctly with the embedded hyphen:
c.aggregate({
$project: {
hostname: 1,
"total-cores": {$multiply: ["$processors.sockets","$processors.cores"]},
virtual: 1,
_id: 0
}
});

Related

Display field document in mongoDB after execute Query aggregate

This is an example of a data document
{
"_id" : ObjectId("5f437e7846103b2ad0fc5d7d"),
"order_no" : "O-200824-AGFJDQW",
"shipment_no" : "S-200824-AGWCRRM",
"member_id" : 2200140,
"ponta_id" : "9990010100280214",
"plu" : 14723,
"product_name" : "AQUA Air Mineral Botol Air Pet 600ml",
"qty" : 2,
"store_id" : "TD46",
"stock_on_hand" : 0,
"transaction_date" : ISODate("2020-08-24T08:28:29.931Z"),
"created_date" : ISODate("2020-08-24T08:46:48.441Z")
}
this is the data query that I run
var bulan = 12 //month is written with number. example: August = 8
db.log_stock_oos.aggregate([
{
$project: {
month: {
$month: '$transaction_date'
}
}
},
{
$match: {month: bulan}
}
]);
but the result is like this after I run the query
{
"_id" : ObjectId("5f44689607fe453fbfba433e"),
"month" : 12
}
how to make the output exactly like the document display that I attached above??
this is my reference
When you use the projection, its kind of if your value 1 then include the field, if your value 0 then exclude the field from the whole documents. Projection
You can do two things
Use the projection
db.collection.aggregate([
{
$project: {
month: {
$month: "$transaction_date"
},
order_no: 1,
shipment_no: 1,
member_id: 1,
//other fields like above with the value 1
}
},
// match stages
])
Use $addFields
use $addFields incited of $project in your code. If will create a filed if not exists in your document, else it will overwrite the field

Sum of column inside a array in Mongodb

I am new to MongoDB and trying to find the sum of device_status out of
device_execution array for a given serial number.e.g serial number
ELMESR0719PXN6 has two device status respectively 200 and 400 at a given
time.After each 5 minutes device status keep coming and we are storing it.So
we want to add the sum of status 200 or 400 per serial number.Below is the
document which contains all the details :
Output should be like below :
Serial number Device_status Sum
ELMESR0719PXN6 200 5
400 5
{
"_id" : ObjectId("5e57b3376c8b9aabd5312840"),
"ve_serial_number" : "ELMESR0719PXN6",
"ve_type" : "eVE",
"start_ts" : "2020-02-19T00:00:00.000+00:00",
"end_ts" : "2020-02-19T23:59:59.999+00:00",
"device_execution" : [
{
"execution_time" : "2020-02-19T00:00:00.000+00:00",
"device_status" : {
"200" : 4,
"400" : 2
}
},
{
"execution_time" : "2020-02-19T00:02:00.000+00:00",
"device_status" : {
"200" : 1,
"400" : 3
}
}
]
}
Can you please help me in finding the solution?Thanks in advance.
This one gives desired result:
db.collection.aggregate([
{ $unwind: "$device_execution" },
{
$group: {
_id: "$ve_serial_number",
"400": { $sum: "$device_execution.device_status.400" },
"200": { $sum: "$device_execution.device_status.200" }
}
}
])
Result:
{
"_id" : "ELMESR0719PXN6",
"200" : 5.0,
"400" : 5.0
}
The format is not the final one, this I leave up to you.
I think you can achieve this by using $unwind aggregation operator for "device_execution" field
Then you can just $group them by "ve_serial_number" and "device_status" and sum them up.

How to set keys in mongoDB aggregation?

The idea is to go from a collection of documents like this:
{
"_id" : ObjectId("58ff4fa372ac97344d5672c2"),
"direction" : 1,
"post" : ObjectId("58ff4ea572ac97344d5672c1"),
"user" : ObjectId("586b84239ae9590ab66bd3ad")
}
{
"_id" : ObjectId("58ff4c9f2952d7341d4afc0c"),
"direction" : -1,
"post" : ObjectId("58fc15a3fb3bed0fd54bfd95"),
"user" : ObjectId("586b84239ae9590ab66bd3ad")
}
To this:
[
//post: direction
"58ff4ea572ac97344d5672c1": 1,
"58fc15a3fb3bed0fd54bfd95": -1
]
I can't seem to find anything in the MongoDB Aggregation docs that allows you to set the key name using the value of another field.
I'm expecting this code to work, but I can see why it doesn't. It thinks that "$post" refers to a MongoDB expression.
db.votes.aggregate([
{$group: {
_id: null,
entries: {
$addToSet: {
"$post": "$direction"
}
}
}}
])

initiate mongodb replica set

I am running the following in a script to automate the initiation of a replica set:
var cfg = { _id: 'rs0',
members: [
{ _id: 0, host: '192.168.1.46:27017'},
{ _id: 1, host: '192.168.1.51:27017'},
{ _id: 2, host: '192.168.1.48:27017'}
]
};
var error = rs.initiate(cfg);
printjson(error);
However I am getting :
{ "ok" : 0, "errmsg" : "Missing expected field \"version\"", "code" : 93 }
After I run the script and am not sure why.
I have tried running the script locally as well using the following:
mongo 192.168.1.46:27017 /opt/scripts/initreplset.js
I am using mongodb v3.2.
I'm having the same problem now, probably is something quite new,
anyway it seems that the version field is now mandatory.
From the official documentation:
version
Type: int
An incrementing number used to distinguish revisions of the replica
set configuration object from previous iterations of the
configuration.
So probably you just need to add this number.
I.e.:
{
"_id" : "rs0",
"version" : 1,
"members" : [
{
"_id" : 1,
"host" : "mongodb0.example.net:27017"
}
]
}

Upsert with pymongo and a custom _id field

I'm attempting to store pre-aggregated performance metrics in a sharded mongodb according to this document.
I'm trying to update the minute sub-documents in a record that may or may not exist with an upsert like so (self.collection is a pymongo collection instance):
self.collection.update(query, data, upsert=True)
query:
{ '_id': u'12345CHA-2RU020130304',
'metadata': { 'adaptor_id': 'CHA-2RU',
'array_serial': 12345,
'date': datetime.datetime(2013, 3, 4, 0, 0, tzinfo=<UTC>),
'processor_id': 0}
}
data:
{ 'minute': { '16': { '45': 1.6693091}}}
The problem is that in this case the 'minute' subdocument always only has the last hour: { minute: metric} entry, the minute subdocument does not create new entries for other hours, it's always overwriting the one entry.
I've also tried this with a $set style data entry:
{ '$set': { 'minute': { '16': { '45': 1.6693091}}}}
but it ends up being the same.
What am I doing wrong?
In both of the examples listed you are simply setting a field ('minute')to a particular value, the only reason it is an addition the first time you update is because the field itself does not exist and so must be created.
It's hard to determine exactly what you are shooting for here, but I think what you could do is alter your schema a little so that 'minute' is an array. Then you could use $push to add values regardless of whether they are already present or $addToSet if you don't want duplicates.
I had to alter your document a little to make it valid in the shell, so my _id (and some other fields) are slightly different to yours, but it should still be close enough to be illustrative:
db.foo.find({'_id': 'u12345CHA-2RU020130304'}).pretty()
{
"_id" : "u12345CHA-2RU020130304",
"metadata" : {
"adaptor_id" : "CHA-2RU",
"array_serial" : 12345,
"date" : ISODate("2013-03-18T23:28:50.660Z"),
"processor_id" : 0
}
}
Now let's add a minute field with an array of documents instead of a single document:
db.foo.update({'_id': 'u12345CHA-2RU020130304'}, { $addToSet : {'minute': { '16': {'45': 1.6693091}}}})
db.foo.find({'_id': 'u12345CHA-2RU020130304'}).pretty()
{
"_id" : "u12345CHA-2RU020130304",
"metadata" : {
"adaptor_id" : "CHA-2RU",
"array_serial" : 12345,
"date" : ISODate("2013-03-18T23:28:50.660Z"),
"processor_id" : 0
},
"minute" : [
{
"16" : {
"45" : 1.6693091
}
}
]
}
Then, to illustrate the addition, add a slightly different entry (since I am using $addToSet this is required for a new field to be added:
db.foo.update({'_id': 'u12345CHA-2RU020130304'}, { $addToSet : {'minute': { '17': {'48': 1.6693391}}}})
db.foo.find({'_id': 'u12345CHA-2RU020130304'}).pretty()
{
"_id" : "u12345CHA-2RU020130304",
"metadata" : {
"adaptor_id" : "CHA-2RU",
"array_serial" : 12345,
"date" : ISODate("2013-03-18T23:28:50.660Z"),
"processor_id" : 0
},
"minute" : [
{
"16" : {
"45" : 1.6693091
}
},
{
"17" : {
"48" : 1.6693391
}
}
]
}
I ended up setting the fields like this:
query:
{ '_id': u'12345CHA-2RU020130304',
'metadata': { 'adaptor_id': 'CHA-2RU',
'array_serial': 12345,
'date': datetime.datetime(2013, 3, 4, 0, 0, tzinfo=<UTC>),
'processor_id': 0}
}
I'm setting the metrics like this:
data = {"$set": {}}
for metric in csv:
date_utc = metric['date'].astimezone(pytz.utc)
data["$set"]["minute.%d.%d" % (date_utc.hour,
date_utc.minute)] = float(metric['metric'])
which creates data like this:
{"$set": {'minute.16.45': 1.6693091,
'minute.16.46': 1.566343,
'minute.16.47': 1.22322}}
So that when self.collection.update(query, data, upsert=True) is run it updates those fields.