Dictionary style access returning None in MongoDB - mongodb

I have been trying to access a database in mongodb and then modifying the particular fetched data into key-value pair for further issue. Although, my code works fine with other collections. But, It's giving me some errors with this.
1: Here is the snippet of my code which was giving the first error:
kpi = sample["kpi"]
for proc in kpi:
volume_used = int(float(kpi[proc]["percent"][:-1]))
volume_free = 100 - volume_used
volume_name = kpi[proc]["folder"]
vol_first = [volume_name, volume_used]
vol_second = [volume_name, volume_free]
data_first.append(vol_first)
data_second.append(vol_second)
value_first.append({"key": "volume used", "values": data_first})
value_first.append({"key": "volume free", "values": data_second})
disk_data.append({
"key": dev["device_name"] + "," + dev["ipaddr"],
"values": value_first
})
print disk_data
From this, The error i got was like this:
File "stats_server.py", line 1547, in getD3DiskData_columnchart
"key": dev["device_name"] + "," + dev["ipaddr"],
TypeError: unsupported operand type(s) for +: 'float' and 'str'
Then, I modified the device_name which was of float format to string.
2: Modified code:
kpi = sample["kpi"]
for proc in kpi:
volume_used = int(float(kpi[proc]["percent"][:-1]))
volume_free = 100 - volume_used
volume_name = kpi[proc]["folder"]
vol_first = [volume_name, volume_used]
vol_second = [volume_name, volume_free]
data_first.append(vol_first)
data_second.append(vol_second)
value_first.append({"key": "volume used", "values": data_first})
value_first.append({"key": "volume free", "values": data_second})
disk_data.append({
"key": str(dev["device_name"]) + "," + dev["ipaddr"],
"values": value_first
})
print disk_data
Then, i started getting this error.
File "stats_server.py", line 1530, in getD3DiskData_columnchart
kpi = sample["kpi"]
TypeError: 'NoneType' object has no attribute '__getitem__'
The line kpi = sample["kpi"] returns the documents from the particular collection.
The query i used to fetch the data is:
disk_util_coll = db[kpi_meta]
disk_docs = disk_util_coll.find_one()
sample = disk_docs
Where, kpi_meta is the collection's name.
The document kpi will be containing the data i need as:
"kpi" : {
"none" : {
"usage" : "0",
"folder" : "/run/shm",
"percent" : "0%",
"free" : "246M",
"dev" : "none"
},
"tmpfs" : {
"usage" : "256K",
"folder" : "/run",
"percent" : "1%",
"free" : "99M",
"dev" : "tmpfs"
},
"/dev/sda1" : {
"usage" : "1.2G",
"folder" : "/",
"percent" : "74%",
"free" : "404M",
"dev" : "/dev/sda1"
},
"udev" : {
"usage" : "4.0K",
"folder" : "/dev",
"percent" : "1%",
"free" : "238M",
"dev" : "udev"
}
Any sort of help will be appreciated.
Let me know, if i am supposed to give something more from my side.
Thank you

The error message:
TypeError: 'NoneType' object has no attribute '__getitem__'
means that "sample" is None. This means your find_one query didn't return a document. That is, the query didn't match any documents in the collection. Check that find_one() returns a document before trying to access its fields.

Related

I get an error trying to import the rcdb tutorial json data to MongoDB via Compass

I am trying to import JSON data into MongoDB via Compass and I get this error
Unexpected token ":" (0x3A) in JSON at position 10 while parsing near " \"_id\" : ObjectId(\"57efaead..." in C:\Users\Michael.Pares\source\repos\forge-rcdb.nodejs\resources\db\rcdb.models.json
> 1 | "_id" : ObjectId("57efaead77c8eb0a560ef465"),
| ^
2 | "name" : "Car Seat",
3 | "env" : "Local",
4 | "layout" : {
Here is what the JSON looks like
{
"_id" : ObjectId("57efaead77c8eb0a560ef465"),
"name" : "Car Seat",
"env" : "Local",
"layout" : {
"type" : "flexLayoutRight",
"rightFlex" : 0.35
},
"model" : {
"urn" : "dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6bGVlZnNtcC1mb3JnZS9zZWF0LmR3Zg",
"path": "https://sbhehe.github.io/sb233/carseat/0.svf",
"name" : "Car Seat"
},
Any idea why this is happening?
In this case, you can use the option ADD DATA > Insert Document to certify that your schema is correct.
For that, you won't need ObjectId to pass the id of the document.
The JSON below is in the proper format.
{
"_id": "57efaead77c8eb0a560ef465",
"name": "Car Seat",
"env": "Local",
"layout":{
"type": "flexLayoutRight",
"rightFlex": 0.35
},
"model":{
"urn": "dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6bGVlZnNtcC1mb3JnZS9zZWF0LmR3Zg",
"path": "https://sbhehe.github.io/sb233/carseat/0.svf",
"name": "Car Seat"
}
}
If you compare it with the one you have (with textcompare) you can see that is also missing one } at the end of your JSON.

How to query and get value from list in single document

I am trying to query a mongodb list in a single document. As shown below, I would like to match the code and get wheels value. if code = car then query should return wheels and allowed value for that list element. Below is a list from single document.
"vehicles" : [
{
"code" : "car",
"wheels":4,
"allowed": True
},
{
"code" : "Tuk Tuk",
"wheels":4
"allowed":True
},
{
"code" : "Bike",
"wheels":4
"allowed":False
}]
you can try like this
db.collectionName.find({"vehicles.code" : "car" }, {"vehicles.wheels" : 1 , "vehicles.allowed" : 1}).pretty()
here "vehicles.code" : "car" is the filter and "vehicles.wheels" : 1 will display the only wheels value and won't display any other fields

Mongodb query to return field value

I am trying to construct a Mongodb query to return a field value. My JSON looks like this:
"question" : "Global_Deployment",
"displayOrder" : 1,
"answerOptions" : {
"fieldId" : "1001",
"fieldType" : "radiobutton",
"fieldName" : "Global Deployment?",
"fieldLabel" : "Global Deployment?",
"helpText" : "Help will go here",
"emailTagFormControl" : "Global_Deployment?",
"source" : "custom",
"status" : "active",
"required" : "true",
"multiSelect" : "false",
"purgeFlag" : "false",
"enableAuditTrack" : "false",
"fields" : [],
"fieldValue" : "Yes",
"options" : [
{
"optionName" : "Yes"
},
{
"optionName" : "No"
}
],
"comments" : {
"commentId" : "C1001",
"commentDetails" : []
}
My query to reach the field with the fieldName "Global Deployment" is this:
db.getCollection('requests').find({"sections.questions.answerOptions.fieldName":"Global Deployment?"})
What I want to know is what to add to this query to return the value of "fieldValue", which is on a different line in the JSON. I am new to Mongodb. Any help would be greatly appreciated.
1) If you've multiple documents in DB with "fieldName" : "Global Deployment?", then .find() would return all the matching documents i.e; in the output what you get is an array of documents then you need to iterate through the array to get answerOptions.fieldValue for each document, Check the below scenario, as I've explained there are chances of getting multiple documents if "sections.questions.answerOptions.fieldName" is not an unique field.
db.getCollection('requests').find({"sections.questions.answerOptions.fieldName":"Global Deployment?"}, {'sections.questions.answerOptions.fieldValue':1})
Output of find :
/* 1 */
[{
"_id" : ObjectId("5d4e19826e173840500f5674"),
"answerOptions" : {
"fieldValue" : "Yes"
}
},
/* 2 */
{
"_id" : ObjectId("5d4e19826e073840500f5674"),
"answerOptions" : {}
}]
If you only need documents which has fieldValue in it then do this :
db.getCollection('requests').find({"sections.questions.answerOptions.fieldName":"Global Deployment?", 'sections.questions.answerOptions.fieldValue':{$exists: true}}, {'answerOptions.fieldValue':1})
Ok now you've array of documents then do iterate thru each to retrieve your value, check this mongoDB cursor tutorial .
2) If you think fieldName is unique across collection, then you can use .findOne() , which would exactly return one document (In case if you've multiple matching documents it would return first found doc) :
db.getCollection('requests').findOne({"sections.questions.answerOptions.fieldName":"Global Deployment?"}, {'sections.questions.answerOptions.fieldValue':1})
Output of findOne :
{
"_id" : ObjectId("5d4e19826e173840500f5674"),
"answerOptions" : {
"fieldValue" : "Yes"
}
}
If you see .find({},{}) has two arguments, second one is called projection which literally be useful if you want to retrieve only required fields in the response, By default mongoDB will return the entire document what ever you've posted in the question will be retrieved, Data in mongoDB flows as JSON's so operating will be similar to using JSON's, Here you can retrieve the required fields out of result, but for best use of network efficiency if you don't need entire document you'll only get the required fields using projection.
You can specify the second condition separated by comma. Either you are trying to filter data with $and or with $or
With simple approach:
{"sections.questions.answerOptions.fieldName":"Global Deployment?","sections.questions.answerOptions.fieldValue":"Yes" }
By using $and method:
.find(
{
$and: [
{"sections.questions.answerOptions.fieldName":"Global Deployment?"},
{"sections.questions.answerOptions.fieldValue":"Yes"}
]
}
)
Same way you can use $or method. Just replace $and with $or.
Edit:
If you want to retrieve specific value (in your case fieldValue), query would be:
db.getCollection('requests').find({
"sections.questions.answerOptions.fieldName":"Global Deployment?"
}).map(function(item){
return item.fieldValue
})
The correct answer here is the method .distinct() (docs)
In your case try it like this:
db.getCollection('requests').find({"sections.questions.answerOptions.fieldName":"Global Deployment?"}).distinct('fieldValue');
That will return only the value you want.
If you use findOne you can use dot notation.
For example, if we start with creating a collection to test using the following to get close to your sample:
db.stackOverflow.insertOne({
sections: {
questions: {
question: "Global_Deployment",
displayOrder: 1,
answerOptions: {
fieldId: "1001",
fieldType: "radiobutton",
fieldName: "Global Deployment?",
fieldLabel: "Global Deployment?",
helpText: "Help will go here",
emailTagFormControl: "Global_Deployment?",
source: "custom",
status: "active",
required: "true",
multiSelect: "false",
purgeFlag: "false",
enableAuditTrack: "false",
fields: [],
fieldValue: "Yes",
options: [
{
optionName: "Yes",
},
{
optionName: "No",
},
],
comments: {
commentId: "C1001",
commentDetails: [],
},
},
},
},
})
then, this query will return "Yes".
db.stackOverflow.findOne({}).sections.questions.answerOptions.fieldValue

Get one element from the array of results by index

So every user has 0-3 items in the database. I don't have their indexes, I sort them by creation date, from oldest to youngest. I was wondering if it is possible to get the element from result array by its index by native mongo/mongoose tools.
For example I have these 3 documents in DB for user theguy:
{ "_id" : 1, "name" : "theguy", otherdata: ["data 1", "data 2"] }
{ "_id" : 10, "name" : "theguy", otherdata: ["data 1", "data 2"] }
{ "_id" : 333, "name" : "theguy", otherdata: ["data 1", "data 2"] }
_id will be ObjectId
Then user will try to get some data. He inputs a number in the range from 1 to 3. There can be 0, 1, 2 or 3 entries in database under his name. The example above displays the situation when user has all 3 entries filled. But user doesn't care about all of them right now, he entered the index, he needs only second result out of these 3.
What works for me right now is this:
//user defined the index
index = 2;
//search all docs by this user, but get only ids
let usrlist = await User.find({"name": name}).distinct('_id');
//based on the ids array we can now request exact second document from the database:
//usrlist[index-1] or usrlist[1]
let exactusr = await User.findOne({"_id": usrlist[index-1]});
So the result for exactusr will be:
{ "_id" : 10, "name" : "theguy", otherdata: ["data 1", "data 2"] }
I try to minimize the load by getting only ids, instead of all 3 documents at once. Now the thing is, well, this doesn't look "nice". Getting an array of _id to create another query based on that doesn't seem optimal. And at the end, I don't even know what is better: to do 2 queries(as above) or do 1 query for all user documents and choose the one user needs by index. Documents may be kind of big, containing up to 12000 characters each.
So looking for native ways I found $slice, but I don't think it works with the result array, or I don't understand how.
My attempt of using $slice:
index = 2;
usr = await User.find({"name": name}, {$slice: [index-1, 1]});
Result:
[ {"_id" : 1}, {"_id" : 10}, {"_id" : 333} ]
Expected result:
{ "_id" : 10, "name" : "theguy", otherdata: ["data 1", "data 2"] }
Any ideas? Or other methods that I could make this work?
I created a collection called "sample" and inserted the sample data that you provided.
db.sample.aggregate([{$match : {"name": "theguy"}}]);
{ "_id" : 1, "name" : "theguy", "otherdata" : [ "data 1", "data 2" ] }
{ "_id" : 10, "name" : "theguy", "otherdata" : [ "data 1", "data 2" ] }
{ "_id" : 333, "name" : "theguy", "otherdata" : [ "data 1", "data 2" ] }
Initialize a variable index : var index=1;
Now if we consider the above data, the indexes of the three rows would be 0,1,2. If I want to retrieve the 2nd row with _id : 10, then the index is supposed to be 1. In that case, the aggregate query would look like :
db.sample.aggregate([
{ $match : {"name": "theguy"}},
{ $skip : index},
{ $limit : 1 }
]);
In case you want your index value to mean the position i.e. in this case the position is 2, then modify the query like :
var index=2;
db.sample.aggregate([
{ $match : {"name": "theguy"}},
{ $skip : index-1},
{ $limit : 1 }
]);
Try this solution & let us know, if it worked for you!

How to access data from a nested array structured collection

I have the following structure in my MongoDB .
I have a nested structure of my collection named chains which is shown below .
I am trying to access options of a particular date as shown below which is 2015-01-17 in my case .
db.chains.find({ "symbol" : "UBSC" ,"option_exp.expiration_dt" : "2015-01-17"}).pretty()
But the following query above is returning me all the data related to that Symbol .
{
"_id" : ObjectId("52000a90d293b0e4134e8c35"),
"symbol" : "UBSC",
"option_exp" : [
{
"expiration_dt" : "2015-01-17",
"options" : [
{
"mult" : "10"
},
{
"mult" : "10"
}
]
},
{
"expiration_dt" : "2014-01-18",
"options" : [
{
"prem_mult" : "10"
},
{
"prem_mult" : "10"
}
}
]
}
],
}
This is the way i was trying to access through java
BasicDBObject query = new BasicDBObject();
query.append("symbol", "UBSC");
query.append("option_exp.expiration_dt", "2015-01-17");
Could anybody please help me as how to access data of a particular date .
Use $elemMatch to limit content of option_exp array field that is included in result:
db.chains.find({symbol : "UBSC" ,"option_exp.expiration_dt" : "2015-01-17"},
{option_exp: {$elemMatch: {expiration_dt: "2015-01-17"}}})
This will select documents which have symbol equal to "UBSC" and option_exp array items with expiration_dt equal to "2015-01-17". Then we limit option_exp array content to items which have required expiration date (otherwise whole document will all option_exp items will be returned).