How to add value to existing value using PyMongo - python

I am trying to update/create a new dataset and combine the previous value with the new one.
This is how it looks like in my Python script right now.
dailyDataset = {
"pId" : pub,
"oId" : off,
"payout" : +addPayout,
}
db[dbName].update( { 'pId' : publisher, 'oId' : offer.id }, {"$set" : dailyDataset }, True)
What I try to achieve is, if the dataset pId and oId exists use the current value from "payout" and add the value from addPayout.
E.g. payout = 1.22 and addPayout = 1.22 result should be 2.44.
Any tip is welcome.
Thanks!

You can use the $inc operator:
db[dbName].update( { 'pId' : publisher, 'oId' : offer.id }, {"$inc" : {'payout':1.22}}, True)

Related

How to know the last time a product has been updated MongoD?

I am working on a project where I want to filter by the products that hasn't been updated in 2 months or a determinated date.(that don't have a new item price in the last 2 months or any other date I want to)
I want to do the script in python.
All my db are json that follow this estructure:
And to access it i do mongo_client[db_name][coll_name] and then i normally use .find() or .aggregate()
{
"_id" : ObjectId("6188f511091533324af78fbf"),
"market" : "x",
"product" : "apple",
"item_price_history" : [
{
"item_price" : 219.0,
"date" : ISODate("2021-04-08T15:30:43.000Z")
},
{
"item_price" : 248.0,
"date" : ISODate("2021-04-22T08:02:28.000Z")
}
Do you have any idea of how can I do that? I use the lastest version of Python and Robo 3T-1.4
Thanks in advance
You can look at the data in the item_price_history to check when that field was last updated. But you don't seem to have a way to track when the other field were updated.
Going forward, you could try adding a pre-save hooks to store the last updated datetime if you're using an ODM like MongoEngine.
Refer pre_save method here.
import dateutil.parser
list_to_sort = {
"market" : "x",
"product" : "apple",
"item_price_history" : [
{
"item_price" : 219.0,
"date" : "2021-04-08T15:30:43.000Z"
},
{
"item_price" : 248.0,
"date" : "2021-04-22T08:02:28.000Z"
}]
}
candidates = list_to_sort.values()
for item in candidates:
if isinstance(item,list):
list_to_sort = item
def myfunc(item):
time = dateutil.parser.parse(item["date"])
return time.timestamp()
list_to_sort.sort(key=myfunc)
print(list_to_sort)
this will sort the list based on custom function myfunc

Delete all documents returned in a find().limit()

I'm using db.collection.find({}, {'_id': False}).limit(2000) to get the documents from a collection. This documents are sent to a Facebook API, after the API return success this documents need to be deleted from the collection.
My main doubt is:
Is there a way to I delete all this 2000 documents withou using a for
loop? I know that collection.find returns a cursor, is there a way
to use this cursor in a delete_many?
The structure of my document is:
{
"_id" : ObjectId("61608068887f1a0e2162d94b"),
"event_time" : "1632582893",
"value" : "549.9000",
"contents" : [
{
"product_id" : "1-1",
"quantity" : "1.000000",
"value" : "10"
}
]
}
To solve this problem, based on the comments of #adarsh and #J.F I've used the following code:
rm = [x['_id'] for x in MongoDB(mongo).db.get_collection("DataToSend").find({}, {'_id' : 1}).limit(2000)
MongoDB(mongo).db.get_collection("DataToSend").delete_many({'_id' : { '$in' : list(rm)}})

Extracting and updating a dictionary from array of dictinaries in MongoDB

I have a structure like this:
{
"id" : 1,
"user" : "somebody",
"players" : [
{
"name" : "lala",
"surname" : "baba",
"player_place" : "1",
"start_num" : "123",
"results" : {
"1" : { ... }
"2" : { ... },
...
}
},
...
]
}
I am pretty new to MongoDB and I just cannot figure out how to extract results for a specific user (in this case "somebody", but there are many other users and each has an array of players and each player has many results) for a specific player with start_num.
I am using pymongo and this is the code I came up with:
record = collection.find(
{'user' : name}, {'players' : {'$elemMatch' : {'start_num' : start_num}}, '_id' : False}
)
This extracts players with specific player for a given user. That is good, but now I need to get specific result from results, something like this:
{ 'results' : { '2' : { ... } } }.
I tried:
record = collection.find(
{'user' : name}, {'players' : {'$elemMatch' : {'start_num' : start_num}}, 'results' : result_num, '_id' : False}
)
but that, of course, doesn't work. I could just turn that to list in Python and extract what I need, but I would like to do that with query in Mongo.
Also, what would I need to do to replace specific result in results for specific player for specific user? Let's say I have a new result with key 2 and I want to replace existing result that has key 2. Can I do it with same query as for find() (just replacing method find with method replace or find_and_replace)?
You can replace a specific result and the syntax for that should be something like this,
assuming you want to replace the result with key 1,
collection.updateOne({
"user": name,
"players.start_num": start_num
},
{ $set: { "players.$.results.1" : new_result }})

update nth document in a nested array document in mongo

I need to update a document in an array inside another document in Mongo DB.
{
"_id" : ObjectId("51cff693d342704b5047e6d8"),
"author" : "test",
"body" : "sdfkj dsfhk asdfjad ",
"comments" : [
{
"author" : "test",
"body" : "sdfkjdj\r\nasdjgkfdfj",
"email" : "test#tes.com"
},
{
"author" : "hola",
"body" : "sdfl\r\nhola \r\nwork here"
}
],
"date" : ISODate("2013-06-30T09:12:51.629Z"),
"permalink" : "mxwnnnqafl",
"tags" : [
"ab"
],
"title" : "cd"
}
If I try to update first document in comments array by below command, it works.
db.posts.update({'permalink':"cxzdzjkztkqraoqlgcru"},{'$inc': {"comments.0.num_likes": 1}})
But if I put the same in python code like below, I am getting Write error, that it can't traverse the element. I am not understanding what is missing!!
Can anyone help me out please.
post = self.posts.find_one({'permalink': permalink})
response = self.posts.update({'permalink': permalink},
{'$inc':"comments.comment_ordinal.num_likes": 1}})
WriteError: cannot use the part (comments of comments.comment_ordinal.num_likes) to traverse the element
comment_ordinal should be a substitution, not the index itself. You're treating it like an integer that can be mapped to an ordinal number. I mean you should do something like:
updated_field = "comments." + str(comment_ordinal) + ".num_likes"
response = self.posts.update({'permalink': permalink}, {'$inc': {updated_field: 1}})
Hope this helps.
You are doing it wrong you need to build your query dynamically and the best way to do that is using the str.format method.
response = self.posts.update_one(
{'permalink': permalink},
{'$inc': {"comments.{}.num_likes".format(comment_ordinal): 1}}
)
Also you should consider to use the update_one method for single update and update_many if you need to update multiple documents because update is deprecated.

How to Query this in MongoDB?

My items store in MongoDB like this :
{"ProductName":"XXXX",
"Catalogs" : [
{
"50008064" : "Apple"
},
{
"50010566" : "Box"
},
{
"50016422" : "Water"
}
]}
Now I want query all the items belong to Catalog:50008064,how to?
(the catalog id "50008064" , catalog name "Apple")
You cannot query this in an efficient manner and performance will decrease as your data grows. As such I would consider it a schema bug and you should refactor/migrate to the following model which does allow for indexing :
{"ProductName":"XXXX",
"Catalogs" : [
{
id : "50008064",
value : "Apple"
},
{
id : "50010566",
value : "Box"
},
{
id : "50016422",
value : "Water"
}
]}
And then index :
ensureIndex({'Catalogs.id':1})
Again, I strongly suggest you change your schema as this is a potential performance bottleneck you cannot fix any other way.
This should probably work according to the entry here, although this won't be very fast, as stated in in the link.
db.products.find({ "Catalogs.50008064" : { $exists: true } } )

Categories

Resources