2014-04-10 13 views
12

Sto cercando di ottenere dizionari ordinati in Pymongo. Ho letto che può essere fatto con bson.son.Son. I documenti sono HereCome ottenere dizionari ordinati in pymongo?

Tuttavia, non riesco a farlo funzionare. Non c'è molto su google a riguardo. Ci sono alcune discussioni sulla configurazione di pymongo per dirle di usare gli oggetti SON ma senza esempi. Un amico suggerisce di passare un param quando fai una ricerca. Non riusciva a ricordare.

Sono in grado di creare oggetti SON. Ma quando vengono inseriti nel DB e poi tornano fuori, sono solo semplici dicts.

Non sono sicuro quale esempio di codice dare perché non so davvero da dove iniziare. Il frammento di seguito crea un oggetto SON vuoto ogni volta che aggiungo un nuovo utente. Anche l'oggetto 'sub_users' è stato creato con SON. Quando leggo il documento dell'account dal DB, sono solo normali dit pitone.

account['sub_users'][sub_user_name] = bson.SON() 
    with mongo_manager.Collection(CFG.db, 'Users') as users: 
     users.save(account) 

Forse un parametro passato alla ricerca come questa da configurare? Questo era il suggerimento dei miei amici ma non riusciva a ricordare.

with mongo_manager.Collection(CFG.db, 'Users') as users:         
    account = users.find_one({'_id': _id, 'DOC':'OrderedDict}) 

Qualche idea?

risposta

9

È possibile utilizzare bson.son.SON o OrderedDict per memorizzare il dettato ordinato.

E recuperare dati con l'opzione as_class=OrderedDict.

Ecco un esempio:

from collections import OrderedDict 
from pymongo import MongoClient 
import bson 

client = MongoClient() 
sample_db = client['sample'] 
test_col = sample_db['test'] 

test_col.drop() 

data = OrderedDict([("one", 1), ("two", 2), ("three", 3), ("four", 4)]) 
test_col.insert(data) 
print(list(test_col.find({}, {'_id': 0}, as_class=OrderedDict))) 

test_col.drop() 

data = bson.son.SON([("one", 1), ("two", 2), ("three", 3), ("four", 4)]) 
test_col.insert(data) 
print(list(test_col.find({}, {'_id': 0}, as_class=OrderedDict))) 

uscita:

[OrderedDict([(u'one', 1), (u'two', 2), (u'three', 3), (u'four', 4)])] 
[OrderedDict([(u'one', 1), (u'two', 2), (u'three', 3), (u'four', 4)])] 
+0

Risposta stupenda. Grazie. –

+0

+1 intelligente e utile – shx2

+1

C'è qualche differenza nelle prestazioni tra l'uso di un 'OrderedDict' e un oggetto' SON'? Guardando le fonti ([qui] (https://github.com/mongodb/mongo-python-driver/blob/master/bson/son.py#L33) e [qui] (https://github.com) /python/cpython/blob/d4edfc9abffca965e76ebc5957a92031a4d6c4d4/Lib/collections/__init__.py)), entrambe sono sottoclassi di 'dict', ma' OrderedDict' ha un'implementazione C (con un Python puro come fallback) mentre 'SON' sembra avere solo un'implementazione Python ... –

13

Questa soluzione di cui sopra è corretto per le versioni precedenti di MongoDB e il conducente pymongo ma non funziona più con pymongo3 e MongoDB3 + Ora è necessario aggiungere document_class=OrderedDict al costruttore MongoClient. Modifica della risposta di cui sopra per la compatibilità con pymongo3.

from collections import OrderedDict 
from pymongo import MongoClient 
import bson 

client = MongoClient(document_class=OrderedDict) 
sample_db = client['sample'] 
test_col = sample_db['test'] 

test_col.drop() 

data = OrderedDict([("one", 1), ("two", 2), ("three", 3), ("four", 4)]) 
test_col.insert(data) 
print(list(test_col.find({}, {'_id': 0}))) 

test_col.drop() 

data = bson.son.SON([("one", 1), ("two", 2), ("three", 3), ("four", 4)]) 
test_col.insert(data) 
print(list(test_col.find({}, {'_id': 0}))) 

uscita:

[OrderedDict([(u'one', 1), (u'two', 2), (u'three', 3), (u'four', 4)])] 
[OrderedDict([(u'one', 1), (u'two', 2), (u'three', 3), (u'four', 4)])] 
2

In PyMongo v3.2 insert() è obsoleto ed in questo esempio dovrebbe essere sostituito con insert_one(). codice aggiornato è qui sotto:

from collections import OrderedDict 
from pymongo import MongoClient 
import bson 

client = MongoClient(document_class=OrderedDict) 
sample_db = client['sample'] 
test_col = sample_db['test'] 

test_col.drop() 

data = OrderedDict([("one", 1), ("two", 2), ("three", 3), ("four", 4)]) 
test_col.insert_one(data) 
print(list(test_col.find({}, {'_id': 0}))) 

test_col.drop() 

data = bson.son.SON([("one", 1), ("two", 2), ("three", 3), ("four", 4)]) 
test_col.insert_one(data) 
print(list(test_col.find({}, {'_id': 0}))) 

uscita:

[OrderedDict([(u'one', 1), (u'two', 2), (u'three', 3), (u'four', 4)])] 
[OrderedDict([(u'one', 1), (u'two', 2), (u'three', 3), (u'four', 4)])] 
3

Uno standard find() in PyMongo non restituirà un oggetto che di campi sono nello stesso ordine di quella oggetto, se è stato recuperato tramite la shell mongo.

Questo perché, il tipo predefinito restituito è un Dict e l'ordine non è definito.

È possibile utilizzare SON come suggerito. Ecco come l'ho fatto. Adesso l'ordine dei campi sarà rispettato.

Questo è per pymongo == 3.4.0

from bson.codec_options import CodecOptions 
from bson.son import SON 

opts = CodecOptions(document_class=SON) 
collection_son = mongo.db.collection.with_options(codec_options=opts) 

collection_son.find_one({"imsid": '12345'})