How to access to fetched data from mongodb in erlang? - mongodb

I use mongodb-erlang driver for mongo db access in erlang. Some of my command execution:
34> {ok, Conn} = mongo:connect({localhost, 27017}).
{ok,{connection,{"localhost",27017},
<0.89.0>,false,infinity}}
35> {ok, Data} = mongo:do(safe, master, Conn, homeweb, fun() -> mongo:find_one(user, {apartmentId, 1}) end).
{ok,{{'_id',{<<79,180,252,18,220,119,245,66,215,79,71,61>>},
apartmentId,1.0,email,<<"e#mail.com">>,password,
<<"efe6398127928f1b2e9ef3207fb82663">>}}}
Data is a tuple.
For example in php array is returned from find request and I can get id with code like this: $id = $result['_id'];.
The question is: how to access to fetched from db data in Erlang?

By pattern matching. In this case, "Data" holds the result, so you might do something like:
1> {{'_id', {Id}, apartmentId, ApartmentId, email, Email, password, Password}} = Data.
{{'_id',{<<79,180,252,18,220,119,245,66,215,79,71,61>>},
apartmentId,1.0,email,<<"e#mail.com">>,password,
<<"efe6398127928f1b2e9ef3207fb82663">>}}
The words that start with an upper case will hold the values, so for example, you can print them:
2> ApartmentId.
1.0
3> Email.
<<"e#mail.com">>
4> Password.
<<"efe6398127928f1b2e9ef3207fb82663">>
5> Id.
<<79,180,252,18,220,119,245,66,215,79,71,61>>
EDIT: You are actually doing pattern matching when you run your query. Notice the {ok, Data} = on the left side of the = operator. This is effectively matching that the result is a tuple in the form {ok, Data} and since Data is unbound up to that point, it is assigned to the query result.
EDIT2: Since Data in this case is a bson(), you can refer to the erlang bson module (used as a dependency of the mongodb erlang driver): http://api.mongodb.org/erlang/bson/. There are specific functions you can use in this case, like bson:lookup/2 and bson:fields/1, passing as a parameter the bson() document (the result from mongodb:find_one/2)

Related

Nested cursors with mongodb driver in phoenix/elixir

I am using the mongodb driver from https://github.com/ankhers/mongodb to query a mongodb database in an elixir/phoenix project. In another question, I asked about how to query nested jsons. Another issue would be how to query inserted documents. For example, I can do the following in python
date_=db['posts']['name'][name]['date'][date]
Here, 'posts' is the name of the collection, and the others are inserted documents. For example, one 'date' document was inserted through:
db['posts']['name'][name].insert_one({"date":date})
When I want to obtain all the inserted dates in python, I can do
date_list=[]
def get_date(db):
db_posts_name=db['posts']['name'][name]
for date_query in db_posts_name.find():
date_list.append(date_query["date"])
But I am at a loss in elixir/phoenix to do the same thing because if I do something like
list =
:mongo
|> Mongo.find("posts", %{})
|> Enum.fetch(4)
|> elem(1)
|> Map.fetch("name")
|> elem(1)
new_list =
:mongo
|> Mongo.find("posts", %{"name" => list})
another_list=new_list.find("date",%{})
I get error
Called with 3 arguments
%Mongo.Cursor{coll: "posts", conn: #PID<0.434.0>, opts: [slave_ok: true], query: %{"name" => name}, select: nil}
:find
[]
Is there a way to do this ?
Mongo.find returns always a cursor. A cursor is like a streaming api, so you have to
call some function like Enum.take() or Enum.to_list. If you processing very long collections
it is a good idea to use the Stream module instead.
If you want to fetch one document, then you can use Mongo.find_one.
I'm not understanding your example. I assume name is a parameter:
date_list=[]
def get_date(db):
db_posts_name=db['posts']['name'][name]
for date_query in db_posts_name.find():
date_list.append(date_query["date"])
The following code fetches in collection posts all documents which name is equal to the parameter name and returns only the date field:
date_list = :mongo
|> Mongo.find("posts", %{"name" => name}, %{"date" => 1})
|> Enum.map(fn %{"date" => date} -> date end)
By the way you can give elixir-mongodb-driver a try. This implementation supports the bulk api, change streams api and the transaction api as well.

Mongo Go Driver is getting interface conversion error when SetSort used

I would like to change order my documents in Mongo DB using Go. I have valid json string code and i can marshal it successfully in to map[string]int. The sample of this type just like:
[{year 1}, {lastupdated -1}]. The value presents order year field ascending and lastupdated field descending. This struct is aspect of MongoDB understands. Also I'm pass this data into bson.D type. Here is my code:
if queries["order"] != nil {
var unmarshalledOrder map[string]int
json.Unmarshal(queries["order"].([]byte), &unmarshalledOrder)
docRes := make(bson.D, 0)
for field, sort := range unmarshalledOrder {
docRes = append(docRes, bson.DocElem{field, sort})
}
log.Println(docRes)
}
When I print docRes, everthing goes well. But i pass the data to options.Sort function, the function throws interface conversion: interface {} is runtime.errorString, not string panic. Is it a bug on mongo go driver or am i wrong?
Can you post the code you've written which uses the driver? Based on the use of bson.DocElem, I think you're using mgo, but mgo's Query.Sort method takes strings, not documents (https://pkg.go.dev/github.com/globalsign/mgo?tab=doc#Query.Sort).

How to Write bson Array to ResponseWriter

I am writing code in GoLang. As part of it, I generated bson array by querying a collection in MongoDB using github.com/mongodb/mongo-go-driver/mongo, github.com/mongodb/mongo-go-driver/bson. I need to write this response to http.ResponseWriter. When I attempt to do this using json.Marshal(BsonArrayReceived), response that is written to ResponseWriter has different document structure than JSON document structure stored in MongoDB. So, wanted to know the right way to write query results to ResponseWriter.
Let's say there are two documents that meet my query criteria - cat, dog
cat := bson.D{{"Animal", "Cat"}}
dog := bson.D{{"Animal", "Dog"}}
So resultant bson Array I am creating would be something like below
response := bson.A
response = append(response, cat)
response = append(response, dog)
My current code that did not work is below
writer.Header().Set("Content-Type", "application/json")
json.err := json.Marshal(response)
writer.Write(json)
Expected output would be
[{"Animal":"Cat"},{"Animal":"Dog"}]
Actual output I receive is
[{{"Key":"Animal"},{"Value":"Cat"}},{{"Key":"Animal"},{"Value":"Dog"}}]
So my question is how do I write to ResponseWriter so I preserve the JSON document array structure. I prefer not to use custom Marshal/UnMarshal as that would mean solution is specific and need changes if I change JSON structure
Use bons.M instead.
cat := bson.M{"Animal": "Cat"}
dog := bson.M{"Animal": "Dog"}
response := bson.A{}
response = append(response, cat)
response = append(response, dog)
writer.Header().Set("Content-Type", "application/json")
json, _ := json.Marshal(response)
writer.Write(json)

iterating over a list of values of single key in a collection in mongodb

i have a collection of financial data stored in mongodb. each company symbol has its data. the question is how to iterate over the collection and change the value of the key which is the symbol company to print out the whole collection and this is my list of companies ['TSLA','TYO','C','LULU','DTV','SHS',' ZNGA'] and this is my cod which return the data of one company:
from pymongo import MongoClient
import csv
host = "localhost"
port = 27017
databaseName = "finance000"
collection_name = "income"
client = MongoClient(host, port)
database = client[databaseName]
collection = database[collection_name]
def finance_data(symbol):
Earnings_BeforeInterestAndTaxes = symbol['statement'[0]EarningsBeforeInterestAndTaxes']['content']
Total_Revenue = symbol['statement'][0]['TotalRevenue']['content']
return Earnings_BeforeInterestAndTaxes,Total_Revenue
i =collection.find({'symbol':'C'})
with open('D:/INCOMEdata.csv', "w") as output:
writer = csv.writer(output, lineterminator='\n')
for key in i :
print finance_data(key)
writer.writerow(finance_data(key))
If I understood you correctly. You want to retrieve the document/data for a given company. The company is denoted by a symbol example 'TYSLA'.
If that is what you need. Here is how you do it (assuming each symbol is unique)
company_data = collection.find({'symbol':'TYSLA'})
The above will return a dictionary. To access an element within the document you just use:
company_data['profit'] #profit is an example of an attribute name. You can use any attribute you like.
Assuming you have multiple companies with the same symbol. If you used the above command. you will get a cursor. to get each company just do a for loop example:
company_data = collection.find({'symbol':'TYSLA'})
Now to loop:
for one in company_date:
print one['profit'] #python 2.7
Now to edit the say for example the profit attribute use $set
collection.update_one({'symbol':'TYSLA'},{'profit':100})
the above will change TYSLA's company profit to 100
Update
Assuming you have a collection with the symbol being any value of ['TSLA','TYO','C','LULU','DTV','SHS',' ZNGA']. to get the data for any of the symbols you use (assuming symbol contains any of the names (only one name)):
you use the $or as:
collection.find({"$or":[ {'symbol':'TSLA},{'symbol':'TYO},... ]},{}) #the ... are the rest of the names you need
The above returns the whole data for a given symbol. To return the specifics Total_Revenue and Earnings_BeforeInterestAndTaxes you use the following:
collection.find({"$or":[ {'symbol':'TSLA},{'symbol':'TYO},... ]},{'Total_Revenue ':1,'Earnings_BeforeInterestAndTaxes ':1, _id:0 }) #if you remove _id it will always be returned
I hope that helps.

Does Mongodb have a special value that's ignored in queries?

My web application runs on MongoDB, using python and pyMongo. I get this scenario a lot - code that reads something like:
from pymongo import Connnection
users = Connection().db.users
def findUsers(firstName=None, lastName=None, age=None):
criteria = {}
if firstName:
criteria['firstName'] = firstName
if lastName:
criteria['lastName'] = lastName
if age:
criteria['age'] = age
query = users.find(criteria)
return query
I find that kind of messy how I need an if statement for every value that's optional to figure out if it's needs to go into the search criteria. If only there were a special query value that mongo ignored in queries. Then my code could look like this:
def findUsers(firstName=<ignored by mongo>, lastName=<ignored by mongo>, age=<ignored by mongo>):
query = users.find({'firstName':firstName, 'lastName':lastName, 'age':age})
return query
Now isn't that so much cleaner than before, especially if you have many more optional parameters. Any parameters that aren't specified default to something mongo just ignores. Is there any way to do this? Or at-least something more concise than what I currently have?
You're probably better off filtering your empty values in Python. You don't need a separate if-statement for each of your values. The local variables can be accessed by locals(), so you can create a dictionary by filtering out all keys with None value.
def findUsers(firstName=None, lastName=None, age=None):
loc = locals()
criteria = {k:loc[k] for k in loc if loc[k] != None}
query = users.find(criteria)
Note that this syntax uses dictionary comprehensions, introduced in Python 2.7. If you're running an earlier version of Python, you need to replace that one line with
criteria = dict((k, loc[k]) for k in loc if loc[k] != None)