Update mongodb database from python - python

I am having a mongodb database that I want to update. Actually, my code for creating and updating the database is the following:
from pymongo import MongoClient
client = MongoClient()
client = MongoClient('localhost', 27017)
db = client['my_db_values']
res = collection = db['db_values']
res = collection.find({"User": "2145"})
if res.count() == 0:
json_file = {"User": "2145", "Item": {"123456": {"process1": [],"process2": []}}}
temp_json1 = {"timestamp": "2123532158", "process1_value": 0.4, "state": {"B": 0.1, "F": 0.2, "E": 0.3}}
temp_json2 = {"timestamp": "2323532158", "process2_value": 0.2, "P": 0.8}
json_file ["Item"][str(123464)]["process1"].append(temp_json1)
json_file ["Item"][str(123464)]["process2"].append(temp_json2)
temp = db.values
temp_id = temp.insert_one(json_file).inserted_id
else:
for line in res:
counter = 0
for key in line["Item"].keys():
if line["Item"].keys()[counter] == "123464":
collection.update_one({"User": "2145", "Item": {"123464": {"process1":[]}}}, {"$set": {"Item.123464.process2": [
{"timestamp": "21354879546213", "process1_value": 0,
"state": {"B": 0.1, "F": 0.2,
"E": 0.3}}], "Item.123464.process2": [
{"timestamp": "11354879546213", "process2_value": 0, "P": 0.8}]}})
else:
collection.update_one({"User": "2145"},{"$set": {"Item.123464.process1": [{"timestamp": "21354879546213", "process1_value": 0.4, "state": {"B": 0.1, "F": 0.2, "E": 0.3}}], "Item.123464.process2": [{"timestamp": "11354879546213", "process2_value": 0.2, "P": 0.8}]}})
counter = counter + 1
In the first if stetement if the count it is equally to zero I am creating the json file with that specific user, while if it is already there then i need to do the same for Sla and then I need to update the db with new temp_json1 and temp_json2. How can I update a subdocument into my initial document. Actually I want to perform a check to see if there is in the db a user with the specific id (otherwise I want to add him) then if the current item_id does not exist to add the item in the user document (as I did in my code already). Finally, if the item does exist then I want just to add temp_json1 and temp_json2 in the already created subdocument. How can I do so?

What you desire is subdocument querying (querying documents by their nested contents).
You can control this query by using the $elemMatch feature, to specify what matches your query by the contents of your Item subdocument's 123456 subdocument's process1 array.
The Mongo Shell format of the query is the following (for python driver just use the query part):
db.your_collection.find({
"User": "2145",
"Item.123456.process1": {$elemMatch: {$eq: "12345"} }
});
So if your collection is populated with the following 2 documents:
{ "_id" : ObjectId("aaa"), "User" : "2145", "Item" : { "123456" : { "process1" : [ ], "process2" : [ ] } } }
{ "_id" : ObjectId("bbb"), "User" : "2145", "Item" : { "123456" : { "process1" : [ "12345" ], "process2" : [ ] } } }
This query will only return the 2nd document, but the omit the first because its process1 array contents don't contain a "12345".
Hope this helps!

Related

How can I maintain the headers for my JSON data after aggregation?

I am developing a REST API in mongoDB with pymongo. I have several endpoints to execute different queries. I want the JSON data created to maintain the headers it had in the original JSON file.
This is the original JSON data.
"player": "Jamie Vardy", "team": "Leicester City", "assists": 5,
After my endpoint is executed the data returned looks like this:
5,
"Jamie Vardy",
"Leicester City",
The endpoint:
#app.route("/api/v1.0/players/top-assister", methods=["GET"])
def top_assister():
pipeline = [ { "$match" : { "assists" : {"$gte" : 12} } },
{ "$project" : {"assists" : 1, "player" : 1, "team":1}}
]
top_assister = []
for player in players.aggregate(pipeline):
player["assists"]
str(player["player"])
str(player["team"])
top_assister.append([player["assists"], str(player["player"]), str(player["team"])])
return make_response(jsonify(top_assister), 200)

Insert many documents into empty collection, update if document with same key already exist for mongodb

I have this list of dictionaries json_data
json_data = [
{
"CODE": "018906",
"X": "29813.66349",
"Y": "28697.520760000003"
},
{
"CODE": "018907",
"X": "30041.8389",
"Y": "28602.98724"
},
{
"CODE": "018910",
"X": "31966.120789999997",
"Y": "29115.75337"
},
]
I have this mongodb collection code_col.
I want to insert json_data into collection code_col when the collecion is empty. There may be a new json_data next time and if the key CODE is the same, the document should be updated instead of inserted.
I am using python 3.7, pymongo, mongodb 4.2.7.
You just need to set the upsert flag as True.
for j in json_data:
db.code_col.update_one({'CODE': j['CODE']},
{'$set': {'X': j['X'], 'Y': j['Y']}},
upsert=True)
Update: By using bulk_write method we can somewhat reduce the time for this operation.
from pymongo import UpdateOne
requests = []
for j in json_data:
requests.append(UpdateOne({'CODE': j['CODE']},
{'$set': {'X': j['X'], 'Y': j['Y']}},
upsert=True))
db.code_col.bulk_write(requests)

python flask mongodb insert data

how do i insert data to a specific user in python flask mongodb
{
"_id" : ObjectId("5e208aa1f86973bbd7db6e8a"),
"worker_name" : "user1",
"location" : "location1",
"detection" : [ ]
},
{
"_id" : ObjectId("5e208aa1f86973bbd7db6e8b"),
"worker_name" : "user2",
"location" : "location2",
"detection" : [ ]
}
above are my users, I want to insert some data in user1 detection list, below are my code i had tried
def face_detection():
face_module = mongo.db.face_modules
user = mongo.db.users
stream_link = request.form['stream_link']
location = request.form['location']
camera = request.form['camera']
result = {
"location": location,
"stream_url": stream_link,
"worker_name": "user1",
"date": "1/1/2020",
"hour": "9",
"minute": "10",
"second": "25"
}
if user.find({"worker_name": result['worker_name']}).count() > 0:
update_user = user.detection.insert(result)
output = "user updated"
return jsonify({'result': output})
Since the document already exists you need to update it rather than insert, Also as you wanted to insert something into an array it should be through $push, Plus instead of making two DB calls you can use find_one_and_update which will return updated document with this option :: return_document = ReturnDocument.AFTER or will return none incase of no matching document found. Based on that you can return the response. In general you would use insert or insert_one for inserting a new document to colleciton. I'm a bit new to pymongo, Please add the code to check error scenario from DB, Plus test this code & you're feel free to update this answer with any findings..
Try this :
def face_detection():
face_module = mongo.db.face_modules
user = mongo.db.users
stream_link = request.form['stream_link']
location = request.form['location']
camera = request.form['camera']
result = {
"location": location,
"stream_url": stream_link,
"worker_name": "user1",
"date": "1/1/2020",
"hour": "9",
"minute": "10",
"second": "25"
}
resp = user.find_one_and_update(
{"worker_name": result['worker_name']},
{ '$push': {'detection' : result} },
return_document = ReturnDocument.AFTER)
if resp :
return jsonify({'result': resp})
else :
return jsonify({'result': 'No document found'})

Querying large Mongodb collection using pymongo

I want to query my mongodb collection which has more than 5k records, each record has key-value pair like
{
"A" : "unique-value1",
"B" : "service1",
"C" : 1.2321,
...
},
...
here A will always have unique value, B has value like service1, service2, ....service8 and C is some float value.
what I want is to get a record like this with key-value pair.
{
"A" : "unique-value1",
"B" : "service1",
"C" : 1.2321
}
{
"A" : "unique-value2",
"B" : "service2",
"C" : 0.2321
}
{
"A" : "unique-value3",
"B" : "service1",
"C" : 3.2321
}
I am not sure how to do this, earlier I used MapReduce but that time I was needed to generate records with A and C key value paire only but now since i also need B i do not know what should i do.
this is what i was doing
map_reduce = Code("""
function () {
emit(this.A, parseFloat(this.C));
}
""")
result = my_collection.map_reduce(map_reduce, reduce, out='temp_collection')
for doc in result.find({}):
out = dict()
out[doc['_id']] = doc['_id']
out['cost'] = doc['value']
out_handle.update_one(
{'A': doc['_id']},
{'$set': out},
upsert=True
)
Unless I've misunderstood what you need , it looks like you are making this harder than it need be. Just project the keys you want using the second parameter of the find method.
for record in db.testcollection.find({}, { 'A': 1, 'B': 1, 'C': 1}):
db.existingornewcollection.replace_one({'_id': record['_id']}, record, upsert=True)
Full example:
from pymongo import MongoClient
from bson.json_util import dumps
db = MongoClient()['testdatabase']
db.testcollection.insert_one({
"A": "unique-value1",
"B": "service1",
"C": 1.2321,
"D": "D",
"E": "E",
"F": "F",
})
for record in db.testcollection.find({}, { 'A': 1, 'B': 1, 'C': 1}):
db.existingornewcollection.replace_one({'_id': record['_id']}, record, upsert=True)
print(dumps(db.existingornewcollection.find_one({}, {'_id': 0}), indent=4))
gives:
{
"A": "unique-value1",
"B": "service1",
"C": 1.2321
}

Improve the performce of a MongoDB query which uses a "$where" expression

I need to run the following query on a MongoDB server:
QUERY = {
"$and" : [
{"x" : {'$gt' : 1.0}},
{"y" : {'$gt' : 0.1}},
{"$where" : 'this.s1.length < this.s2.length+3'}
]
}
This query is very slow, due to the JavaScript expression which the server needs to execute on every document in the collection.
Is there any way for me to optimize it?
I thought about using the $size operator, but I'm not really sure that it works on strings, and I'm even less sure on how to compare its output on a pair of strings (as is the case here).
Here is the rest of my script, in case needed:
from pymongo import MongoClient
USERNAME = ...
PASSWORD = ...
SERVER_NAME = ...
DATABASE_NAME = ...
COLLECTION_NAME = ...
uri = 'mongodb://{}:{}#{}/{}'.format(USERNAME,PASSWORD,SERVER_NAME,DATABASE_NAME)
mongoClient = MongoClient(uri)
collection = mongoClient[DATABASE_NAME][COLLECTION_NAME]
cursor = collection.find(QUERY)
print cursor.count()
The pymongo version is 3.4.
You can use aggregation framework, which provides $strLenCP to get length of a string and $cmp to compare them:
db.collection.aggregate(
[
{
$match: {
"x" : {'$gt' : 1.0},
"y" : {'$gt' : 0.1}
}
},
{
$addFields: {
str_cmp: { $cmp: [ { $strLenCP: "$s1" }, { $add: [ { $strLenCP: "$s2" }, 3 ] } ] }
}
},
{
$match: {
"str_cmp": -1,
}
}
]
)

Categories

Resources