mongoengine embedded field update - python

this is my schema
class Url_per_date(EmbeddedDocument):
date = DateTimeField()
count = IntField(default=0)
class Daily_visit(Document):
domain = StringField()
count = IntField(default=0)
per_date = ListField(EmbeddedDocumentField('Url_per_date'))
i have collection like this:
{
"_id" : ObjectId("51c97e685aa3b3414c7e406a"),
"_types" : "Daily_visit",
"count" : 1,
"domain" : "yahoo.com",
"per_date" : {
"count" : 1,
"date" : ISODate("2013-05-20T00:00:00Z")
}
}
i need to update yahoo.com by date range. if per_date not have ISODate("2013-05-20T00:00:00Z") i need to create it, if i have it inc__count=1.

In MongoEngine, embedded fields are referenced by replacing dot-notation with double underscores:
Fields on embedded documents may also be referred to using field lookup syntax by using a double-underscore in place of the dot in object attribute access syntax:
http://mongoengine-odm.readthedocs.org/en/v0.6.8/guide/querying.html#filtering-queries

at first your result must be like this
{
"_id" : ObjectId("51c97e685aa3b3414c7e406a"),
"_types" : "Daily_visit",
"count" : 1,
"domain" : "yahoo.com",
"per_date" : [{
"count" : 1,
"date" : ISODate("2013-05-20T00:00:00Z")
}]
}
how create date? create new one for today and select database like this
today = datetime.today()
try:
yahoo_obj = Daily_visit.objects.get(domain="yahoo.com", per_date__date=date)
yahoo_obj.per_date[-1].count += 1
except:
yahoo_obj = Daily_visit.objects.get(domain="yahoo.com")
yahoo_obj.per_date = .... # just append new list

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

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 }})

Urlencode to list in python

finalKeywords = []
#after populating finalKeywords
query = {
"apiKey" : self.apikey,
"country" : country,
"currency" : currency,
"kw" : finalKeywords,
"t" : int(time.time())
}
uri = urllib.urlencode(query, True)
print uri
After decoding uri I get
country=&apiKey=5f0092f1777c3a5ed0de&kw=iphone&kw=android&t=1496924489&currency=usd
While my expected output is
country=&apiKey=5f0092f1777c3a5ed0de&kw[0]=iphone&kw[1]=android&t=1496924489&currency=usd
What to do..? I have been looking for solutions but unable to get.
Like this?
query = {
"apiKey" : self.apikey,
"country" : country,
"currency" : currency,
"kw[]" : finalKeywords,
"t" : int(time.time())
}
If you need to have the positional values in there as well for some reason, this is one way to do it:
query = {
"apiKey" : self.apikey,
"country" : country,
"currency" : currency,
"t" : int(time.time())
}
for p,q in enumerate(finalKeywords):
query["kw[{pos}]".format(pos=p)] = q
Based on the W3C spec for URLs, [ and ] aren't valid in the search string, and so will be escaped by urlencode. With that caveat, you can construct a dictionary with unique keys by using a dictionary comprehension:
kw_dict = { "kw[{}]".format(n): finalKeywords[n] for n in range(0, len(finalKeywords)) }
You can then add this to the other parts of your query as follows:
query = dict({
"apiKey" : self.apikey,
"country" : country,
"currency" : currency,
"t" : int(time.time())
}, **kw_dict)

filtering query for django mongoengine

I have two views with embedded document and list field and need filteringquery
for below criteria:
class myfriends(EmbeddedDocument):
myfriends_ids = StringField()
status = StringField()
class Friends(Document):
friend1 = ReferenceField(User)
myfriendslist = ListField(EmbeddedDocumentField(myfriends))
And stored values just like:
{ "_id" : ObjectId("542506f9bed069156ddd4476"),
"friend1" : ObjectId("542314b7bed0691c5302662c"),
"myfriendslist" : [
{
"myfriends_ids" : "5421ae74bed0691471e95b92",
"status" : "1"
} ]
}
I want query to get specific record based on friend1 and myfriends_ids in django mongoengine.
Friends.objects(myfriendslist__match={"myfriends_ids": "5421ae74bed0691471e95b92", "status": "1"}, friend1=FriendObject)

$addToSet nested nested object using pymongo

As part of a for-in loop in python using pymongo I want to add some nested documents/objects inside a linktype field which is to be within a links field:
neither the links field or linktype field exists before the first such entries are to be added.
What is the commands to do this ?
Here is an item before adding links:
item = {
"_id" : ObjectId("5067c26b9d595266e25e825a"),
"name": "a Name"
}
And after adding one link of type typeA:
toType = "typeA"
to_link = {"_id" : ObjectId("5067c26b9d595266e25e825b"), "property":"value"}
{
"_id" : ObjectId("5067c26b9d595266e25e825a"),
"name": "a Name",
"links" : {
"typeA":{
{"_id" : ObjectId("5067c26b9d595266e25e825b"), "property":"value"}
}
}
}
I have tried:
db.collection.update({"name":"a Name"},{{"links":{"$addToSet":{toType:to_link}}})
which doesnt work.
If I just use:
db.collection.update({"name":"a Name"},{ {"$addToSet":{toType:to_link}} )
that works but that is not what i want.
$addToSet is for adding to an array. To add a new property to an existing embedded object you need to use the $set operator and dot notation as:
db.collection.update({name: 'a name'}, {$set: {'links.' + toType: to_link}})

Categories

Resources