PyMongo Pass "find" function to a MongoDB request - python

My task: copy the information from the field 'ACCOUNT' from one document (123) and paste it into another document (456). Both documents are in the same database and the same collection. This is triggered by a client (Windows) using pymongo:
# ... creating the target_collection object ...
info_id = 123 # the document with this id contains the info which shall be written into the new entry
write_data = target_collection.find_one({'_id': info_id})['ACCOUNT'] # extract the info
update_query = {'$addToSet': {'ACCOUNT': {'$each': [write_data]}}}
target_doc = {'_id': 456}
target_collection.update_one(target_doc, update_query, upsert=True)
This code snippet works totally fine, but it is doing two round trips (fetch the info from 123, write it to 456), which makes the transaction not atomic and slows it down significantly. With the Mongo Shell I am able to do this:
db.audit.update(
{_id: 456},
{$addToSet: {'ACCOUNT': {$each: db.getCollection('audit').findOne({_id: 123})["ACCOUNT"] } } }
);
How can I achieve the same in pymongo? Is it possible to send a query string to the server?
Versions I use:
MongoDB 4.4 (on RHEL 7)
pymongo 3.11.4 (on Windows 10)

Related

Push data to Campaign Monitor using Python

Campaign Monitor is a service where we can send emails to a set of subscribers. We can create multiple lists within Campaign Monitor and add the required users to these lists as subscribers(to whom we can send personalised emails). So, here I am trying to send a set of customers' details like their name, emails, total_bookings, and first_booking to the campaign monitor's list using the API in Python so that I can send emails to this set of users.
More details on campaign monitor: https://www.campaignmonitor.com/api/v3-3/subscribers/
I am new to using Campaign Monitor. I have searched documentation, a lot of posts and blogs for examples on how to push data with multiple custom fields to Campaign Monitor using Python. By default, a list in Campaign Monitor will have a name and an email that can be added, but I want to add other details for each subscriber(here I want to add total_bookings and first_booking data) and Campaign Monitor provides custom fields to achieve this.
For instance:
I have my data stored in a redshift table named customer_details with the fields name, email, total_bookings, first_booking. I was able to retrieve this data from redshift table using Python with the following code.
# Get the data from the above table:
cursor = connection.cursor()
cursor.execute("select * from customer_details")
creator_details = cursor.fetchall()
# Now I have the data as a list of sets in creator_details
Now I want to push this data to a list in the Campaign Monitor using API like request.put('https://api.createsend.com/api/../.../..'). But I am not sure on how to do this. Can someone please help me here.
400 indicated invalid parameters
we can first see the request is POST not PUT
so first change requests.put to requests.post
the next thing is that all the variables need to be sent either as www-formdata or as json body data not sure which
and lastly you almost certainly cannot verify with basic auth ... but maybe
something like the following
some_variables = some_values
...
header = {"Authorization": f"Bearer {MY_API_KEY}"}
data = {"email":customer_email,"CustomFields":[{"key":"total_bookings","value":customer_details2}]}
url = f'https://api.createsend.com/api/v3.3/subscribers/{my_list_id}.json'
res = requests.post(url,json=data,headers=header)
print(res.status_code)
try:
print(res.json())
except:
print(res.content)
after looking more into the API docs it looks like this is the expected request
{
"EmailAddress": "subscriber#example.com",
"Name": "New Subscriber",
"MobileNumber": "+5012398752",
"CustomFields": [
{
"Key": "website",
"Value": "http://example.com"
},
{
"Key": "interests",
"Value": "magic"
},
{
"Key": "interests",
"Value": "romantic walks"
}
],
"Resubscribe": true,
"RestartSubscriptionBasedAutoresponders": true,
"ConsentToTrack":"Yes"
}
which we can see has "EmailAddress" not "email" so you would need to do
data = {"EmailAddress":customer_email,"CustomFields":[{"key":"total_bookings","value":customer_details2}]}
Im not sure if all of the fields are required or not ... so you may also need to provide "Name","MobileNumber",Resubscribe",etc
and looking at "Getting Started" it looks like the publish a python package to make interfacing simpler
http://campaignmonitor.github.io/createsend-python/
which makes it as easy as
import createsend
cli = createsend.CreateSend({"api_key":MY_API_KEY})
cli.subscriber.add(list_id,"user#email.com","John Doe",custom_fields,True,"No")
(which I found here https://github.com/campaignmonitor/createsend-python/blob/master/test/test_subscriber.py#L70)

Firebase Realtime Database Adding/Removing/Updating/Retrieving Data

So, I wanted to move my local database to the Firebase by using Firebase's Realtime Database feature, however, I am struggling a bit as I am completely new to Firebase, and I am using the library called 'pyrebase'
What I am looking for:
database {
userid1 {
mail:"email1"
},
userid2 {
mail:"email2"
},
userid3 {
mail:"email3"}
...
}
My first question is regarding to how to create such structure using Firebase?
If such structure in the realtime database was accomplished, how to update any specific userid's data?
If wanted any of the user to be deleted from the system by just using their userid, how is it done?
And lastly, which is very important, if wanted to retrieve any of the user emails by looking through their userid, how is it retrieved?
What I have done so far:
I have created the realtime database so far
Downloaded and integrated the credentials
p.s literally in need of source related to Firebase.
So, I have finally figured out how to do all of these as shown below:
Inserting Data:
from firebase import firebase
firebase = firebase.FirebaseApplication('https://xxxxx.firebaseio.com/', None)
data = { 'Name': 'Vivek',
'RollNo': 1,
'Percentage': 76.02
}
result = firebase.post('/python-sample-ed7f7/Students/',data)
print(result)
Retrieving Data:
from firebase import firebase
firebase = firebase.FirebaseApplication('https://xxxx.firebaseio.com/', None)
result = firebase.get('/python-sample-ed7f7/Students/', '')
print(result)
Updating Data:
from firebase import firebase
firebase = firebase.FirebaseApplication('https://xxxx.firebaseio.com/', None)
firebase.put('/python-sample-ed7f7/Students/-LAgstkF0DT5l0IRucvm','Percentage',79)
print('updated')
Delete Data:
from firebase import firebase
firebase = firebase.FirebaseApplication('https://xxxx.firebaseio.com/', None)
firebase.delete('/python-sample-ed7f7/Students/', '-LAgt5rGRlPovwNhOsWK')
print('deleted')

Improper data value stored in cloud firestore

I'm using firebase-admin Python SDK to store data into Firestore. However, when I'm calling add() method in my collection reference the data gets stored to Firestore but its format is not proper.
message = {
u'avatar_url': get_avatar_url(user),
u'timestamp': get_utc_timestamp(),
u'event': u'adding_avatar'
}
def add_data(message):
coll_ref.add(message)
When I look into the Firestore collection, I find that the data stored is of the format:
{
avatar_url: aHR0cDovL2,
timestamp: 1569404588,
event: 'adding_avatar'
}
I expect the data to look like this(when viewing from Firebase console):
{
avatar_url: 'https://localhost:8000/images/avatar.png',
timestamp: 1569404588,
event: 'adding_avatar'
}
The type of avatar_url is blob. I don't know why is this happening? What is the standard way to add a python dictionary as a payload to Firestore with appropriate datatype?

Get data from mongodb built using mongoose models and node by python using PyMongo

I have a database built using node and mongodb(using mongoose) that is used to support a website. Basically this uses Schemas. Now, I need to query this database in python using flask and I am using Pymongo for this. This database has only one collection.
app = Flask(__name__)
app.config["MONGO_DBNAME"] = databaseName
app.config["MONGO_URI"] = databaseURL
mongo = PyMongo(app)
db = mongo.db
collection = db[collectionName]
collection_list = collection.find({'model':'familySchema'})
#There is only one entry related to 'familySchema' model.
for document in collection_list:
print(document)
# This is what gets printed
# {'_id': ObjectId('5a8d144970512751d3d9e0d9'), 'model': 'familySchema', 'field': '_id', 'count': 95, '__v': 0}
So, when I query the database, I get the result as shown above. The count key showing 95 is correct as there are 95 entries related to the model(I added them in the website). But I am unable to access them. All I get is the model name and the number of entries in it. I want to access all the entries using that model. I am a beginner in using mongo and need some help in this. Any suggestions on how to do this?
In node, it is done like this.
autoIncrement = require('mongoose-auto-increment');
var UnknownSchema = new Schema({
pictureType: {type: String},
location: {type: String},
leafname: {type: String},
createduser: {type: String},
lastedituser: {type: String},
timestamp: { type: Date, default: Date.now},
});
UnknownSchema.plugin(autoIncrement.plugin,'UnknownSchema');
var addUnknown=mongoose.model('addUnknown', UnknownSchema);
//It is fetched like this
var getUnknown=function(req,res){
addUnknown.find({},function (err,data) {
if(err){
res.send(err);
}else {
res.send(data);
}
})
};

How to do a custom insert inside a python-eve app

I have some custom flask methods in an eve app that need to communicate with a telnet device and return a result, but I also want to pre-populate data into some resources after retrieving data from this telnet device, like so:
#app.route("/get_vlan_description", methods=['POST'])
def get_vlan_description():
switch = prepare_switch(request)
result = dispatch_switch_command(switch, 'get_vlan_description')
# TODO: populate vlans resource with result data and return status
My settings.py looks like this:
SERVER_NAME = '127.0.0.1:5000'
DOMAIN = {
'vlans': {
'id': {
'type': 'integer',
'required': True,
'unique': True
},
'subnet': {
'type': 'string',
'required': True
},
'description': {
'type': 'boolean',
'default': False
}
}
}
I'm having trouble finding docs or source code for how to access a mongo resource directly and insert this data.
Have you looked into the on_insert hook? From the documentation:
When documents are about to be stored in the database, both on_insert(resource, documents) and on_insert_<resource>(documents) events are raised. Callback functions could hook into these events to arbitrarily add new fields, or edit existing ones. on_insert is raised on every resource being updated while on_insert_<resource> is raised when the <resource> endpoint has been hit with a POST request. In both circumstances, the event will be raised only if at least one document passed validation and is going to be inserted. documents is a list and only contains documents ready for insertion (payload documents that did not pass validation are not included).
So, if I get what you want to achieve, you could have something like this:
def telnet_service(resource, documents):
"""
fetch data from telnet device;
update 'documents' accordingly
"""
pass
app = Eve()
app.on_insert += telnet_service
if __name__ == "__main__":
app.run()
Note that this way you don't have to mess with the database directly as Eve will take care of that.
If you don't want to store the telnet data but only send it back along with the fetched documents, you can hook to on_fetch instead.
Lastly, if you really want to use the data layer you can use app.data.driveras seen in this example snippet.
use post_internal
Usage example:
from run import app
from eve.methods.post import post_internal
payload = {
"firstname": "Ray",
"lastname": "LaMontagne",
"role": ["contributor"]
}
with app.test_request_context():
x = post_internal('people', payload)
print(x)

Categories

Resources