Pymongo returns subdocs as dicts instead of SONs? - encoding

Is there a way to have pymongo return subdocs as SONs so they can be successfully passed back in for find queries? GridFS is returning the file._id as a dict instead of a SON; so, the subsequent call to grid_file.GridOut.read is failing to find the grid file. (I know, using dicts as _id is asking for trouble, but I'm dealing w/ an existing db/system.)
I don't see how I can intervene to coerce the file._id into the correctly ordered SON.

The MongoClient.document_class field controls this! Just add document_class=bson.son.SON, to the constructor

Related

Firestore: get an Observable doc from another field which is not the Id

I want to get a single Observable from a collection, but I want to get it from a different field that is not the id. It is possible?
I do not want to do a query and limit to 1. I need to get a Single Observable not an array Observable.
Schema:
Code:
this.afs.doc<Credit>('credits/uid/'+ uid).valueChanges();
Error:
Invalid document reference. Document references must have an even number of segments, but credits/uid/d1Zt8sozYqb6H27lhoJgF1Gx2Cc2 has 3
I am not sure if I understand correctly, but I guess that you want to get document with particular uid field value, not using document id.
This particular error is related with common feature of Firestore, that every document has to be in collection not in document. So path values for documents, (nested as well) are always checked, if the segments (devided by /) number is even ex. collection1/doc1/collection2/doc2/collection3/doc3
As results in your code we have 3 segments (like credits/uid/<uid_value>) so this is the error.
I am not very familiar with angularFire2 itself, but I have done it in JS. The approach is normally to query collection and than use method on the results, which in classic JS returns Query object on which the same methods can be used as on CollectionReference (which extends 'Query' btw - reference 1).
Combining this approach with those references: querying and collection I propose following solution:
this.afs.collection('credits', ref => ref.where('uid', '==', <uid_value>)).valueChanges()
If uid_value will be unique you should get your doc.
Unfortunately I do not have any playground to test the solution so please let me know how it works - or if there will be any additional errors.
I hope it will help! Good Luck!

How to order the fields of the documents returned by the find query in MongoDB? [duplicate]

I am using PyMongo to insert data (title, description, phone_number ...) into MongoDB. However, when I use mongo client to view the data, it displays the properties in a strange order. Specifically, phone_number property is displayed first, followed by title and then comes description. Is there some way I can force a particular order?
The above question and answer are quite old. Anyhow, if somebody visits this I feel like I should add:
This answer is completely wrong. Actually in Mongo Documents ARE ordered key-value pairs. However when using pymongo it will use python dicts for documents which indeed are not ordered (as of cpython 3.6 python dicts retain order, however this is considered an implementation detail). But this is a limitation of the pymongo driver.
Be aware, that this limitation actually impacts the usability. If you query the db for a subdocument it will only match if the order of the key-values pairs is correct.
Just try the following code yourself:
from pymongo import MongoClient
db = MongoClient().testdb
col = db.testcol
subdoc = {
'field1': 1,
'field2': 2,
'filed3': 3
}
document = {
'subdoc': subdoc
}
col.insert_one(document)
print(col.find({'subdoc': subdoc}).count())
Each time this code gets executed the 'same' document is added to the collection. Thus, each time we run this code snippet the printed value 'should' increase by one. It does not because find only maches subdocuemnts with the correct ordering but python dicts just insert the subdoc in arbitrary order.
see the following answer how to use ordered dict to overcome this: https://stackoverflow.com/a/30787769/4273834
Original answer (2013):
MongoDB documents are BSON objects, unordered dictionaries of key-value pairs. So, you can't rely on or set a specific fields order. The only thing you can operate is which fields to display and which not to, see docs on find's projection argument.
Also see related questions on SO:
MongoDB field order and document position change after update
Can MongoDB and its drivers preserve the ordering of document elements
Ordering fields from find query with projection
Hope that helps.

find_one query returns just the fields instead of an entry

I'm currently trying to use pymongo's find_one query. When I run the Mongo Shell and execute a findOne query, it get a document that is returned. However when I try using pymongo's find_one query, I always seem to get just the field names instead of an actual entry.
#app.route("/borough/manhattan/")
def manhattan():
restaurantmanhattan = restaurants.find_one({'borough':'Manhattan'})
json_restaurantmanhattan = []
for restaurant in restaurantmanhattan:
json_restaurantmanhattan.append(restaurant)
json_restaurantmanhattan = json.dumps(json_restaurantmanhattan)
return json_restaurantmanhattan
Once I navigate to http://0.0.0.0:5000/borough/manhattan/ I get the following:
["cuisine","borough","name","restaurant_id","grades","address","_id"]
I believe I should be seeing a document entry that meets the query that it has Manhattan listed in the borough.
I'm at a loss as to how I should be writing the query to return that.
Can anyone explain what I'm seeing?
There are many things wrong with your view.
First as you may already know, find_one return a single document as Python dictionary. So in your for loop, you iterating the dictionary keys.
You really do not need that for loop.
import json
#app.route("/borough/manhattan/")
def manhattan():
restaurant_manhattan = restaurants.find_one({'borough':'Manhattan'})
return json.dumps(restaurant_manhattan)

What's the easiest way to return the results of a query for a given key/value pair in mongo as an array of the values returned?

I have a field called id (not _id) in documents from two collections. I need to compare the contents of the first collection with the second. Basically, I need to know what documents with a given value 'id' exist in collection 'A', but not 'B'. What's the easiest way to build an array of id's from Collection A that I can use to do something like the following. :
db.B.find({id:{$nin: array_of_ids_from_coll_A}})
Please don't get hung up over why I'm using 'id' in this case, and not '_id'. Thanks.
Strictly speaking, this doesn't answer the question of 'how to build an array that...', but I'd iterate over collection A and, for each element, try to find a match in B. If none is found, add to a list.
This has a lot of roundtrips to the database, so it's not very fast, but it's very simple. Also, if A contains a lot of elements, the array of ids might be too large to throw all of them in the $nin, which otherwise would have to be solved by splitting up the array of ids. To make matters worse, $nin isn't efficient with indexes anyway.
I incorrectly assumed that the function 'distinct' returned a set of distinct documents based on a given 'field'. In fact, it returns an array of distinct values, provided a specific field. So, I was able to construct the array I was looking for with db.A.distinct('id'). Thanks to anyone who took the time to read this question, anyway.

Mongoid Query Syntax Question

I need to retrieve a set of answers according to 2 attributes.
This is what i want to do:
# where liker_ids is an array and user_id is a bson in the answer document
feed_answers=Answer.any_in(:liker_ids=>to_use,:user_id.in=>to_use).desc()map{|a|a}
What i ended up doing:
# to use
to_use=[some array of ids]
friend_answers=Answer.any_in(:liker_ids=>to_use).map{|a|a}
liked_answers=Answer.where(:user_id.in=>to_use).map{|a|a}
feed_answers=(friend_answers+ liked_answers).sort{|x,y| y.created_at<=>x.created_at}
The problem is that I do not not know how to combine the 2 queries into one. I have been trying out various combinations, but nothing seems to work. and my hacked together method is highly inefficient of course.
You should do(Missing parameter to desc):
Answer.any_in(:liker_ids=>to_use, :user_id.in=>to_use).desc(:created_at)
But the any_in here is not correctly used, it behaves similar to where in this situation. You probably want or:
Answer.or(:liker_ids=>to_use).or(:user_id.in=>to_use).desc(:created_at)
# or
Answer.any_of({:liker_ids=>to_use}, {:user_id.in=>to_use}).desc(:created_at)
# or
Answer.or({:liker_ids=>to_use}, {:user_id.in=>to_use}).desc(:created_at)
You don't need that map at the end of criteria chain, mongoid criteria are lazy loaded, when they encounter a method which criteria do not respond to. They can also leverage mongodb cursors, so it is advised not to use map if it is not necessary. You should use Criteia#only or Criteria#without if you want to retrieve subset of fields from mongodb.