I have an object that looks something like this in the database, with corresponding MongoEngine models:
{
...
"config" : {
"inner_group" : {
"individuals" : [
{
"entity_id" : "54321",
}
],
},
...
}
...
}
I am trying to query this data using the entity_id field in the object which is part of the individuals collection.
I have tried querying according to the MongoEngine docs but I have not been able to pull the data using the following:
data = Model.objects(config__inner_group__individuals__S__entity_id="54321")
How can I query the entire parent based on the entity_id?
Related
I just started using pymongo. Then, I created a for loop to insert data into MongoDB.
However, when the inserted data and the data in the existing MongoDB are the same ID,
I want to update the data in the existing MongoDB.
I don't know how to do this.
#in mongoDB
collection = [
{"_id" : 1234 ,
"like" : ["dog"]
}, ...
]
#in python
data = [
{ "_id" : 1234 ,
"like" : ["cat"]
}, ...
]
client = pymongo.MongoClient(host)
db = client[collection_name]
col = db[documents_name]
for i in data:
col.insert_one(data)
# result in mongoDB
collection = [
{"_id" : 1234 ,
"like" : ["dog","cat"]
}, ...
]
MongoDB inserts the objects with an ObjectID which becomes the primary identity of the inserted document. This is usually auto generated in the server to keep the uniqueness.
If you want to insert with your own custom ObjectId ( not recommended ) , then you need to pass the data with objectid reference in bson package instead of plain string. Like
{"_id":ObjectId("..."), ..}
And yes, your need is to update if exists, for that you need to use the version of upsert instead of insert.
I have 3 linked documents like:
{'_id':1, 'name':'abc', 'label':'actionA', 'prev':null}
{'_id':2, 'name':'pqr', 'label':'actionB', 'prev':ObjectId('1')}
{'_id':3, 'name':'xyz', 'label':'actionC', 'prev':ObjectId('2')}
Now I want to query a document whose 'name' is 'pqr' and also its previous/linked document should contains 'label' as 'actionA'.
All I want is it should find 'name' and check whether previous liked doc is available, if so then check its previous doc should have 'label' which I want.
It will be preferable if using some 1 line command something like:
db.collection.find({'$and'[{'name':'pqr'},{'prev': <gotoprev>({'label':'actionA'})}]})
you can achieve this using aggregation
MongoDB 3.4 Solution
take advantage of the $graphLookup operator:
db.collection.aggregate([
{
$match:{
"name":"pqr"
}
},
{
$graphLookup:{
from:"collection",
startWith:"$prev",
connectFromField:"prev",
connectToField:"_id",
as:"parent",
maxDepth:1,
restrictSearchWithMatch:{
label:"actionA"
}
}
}
])
Mongodb 3.2
filter out document where name != 'pqr' in a $match stage
link parent an child with $lookup
unwind the resulting array with $unwind
finally filter out document where parent.label != 'actionA'
here is the query:
db.collection.aggregate([
{
$match:{
"name":"pqr"
}
},
{
$lookup:{
from:"collection",
localField:"prev",
foreignField:"_id",
as:"prev"
}
},
{
$unwind:"$prev"
},
{
$match:{
"prev.label":"actionA"
}
}
])
You can denormalise and store prev_label also in the referenced document (NoSQL way).
{'_id':1, 'name':'abc', 'label':'actionA', 'prev':null}
{'_id':2, 'name':'pqr', 'label':'actionB', 'prev':ObjectId('1'),'prev_label': 'actionA'}
{'_id':3, 'name':'xyz', 'label':'actionC', 'prev':ObjectId('2'),'prev_label': 'actionB'}
Then you can use find query for the result
db.collection.find({'$and'[{'name':'pqr'},{'prev_label': 'actionA'}]})
If label in original document is changed you can keep them updated in referenced documents with an update query
db.collection.update({'prev': updatedDocumentId},{'$set': {'prev_label': newLabel}}, multi=True)
I have this Document in mongo engine:
class Mydoc(db.Document):
x = db.DictField()
item_number = IntField()
And I have this data into the Document
{
"_id" : ObjectId("55e360cce725070909af4953"),
"x" : {
"mongo" : [
{
"list" : "lista"
},
{
"list" : "listb"
}
],
"hello" : "world"
},
"item_number" : 1
}
Ok if I want to push to mongo list using mongoengine, i do this:
Mydoc.objects(item_number=1).update_one(push__x__mongo={"list" : "listc"})
That works pretty well, if a query the database again i get this
{
"_id" : ObjectId("55e360cce725070909af4953"),
"x" : {
"mongo" : [
{
"list" : "lista"
},
{
"list" : "listb"
},
{
"list" : "listc"
}
],
"hello" : "world"
},
"item_number" : 1
}
But When I try to pull from same list using pull in mongo engine:
Mydoc.objects(item_number=1).update_one(pull__x__mongo={'list': 'lista'})
I get this error:
mongoengine.errors.OperationError: Update failed (Cannot apply $pull
to a non-array value)
comparising the sentences:
Mydoc.objects(item_number=1).update_one(push__x__mongo={"list" : "listc"}) # Works
Mydoc.objects(item_number=1).update_one(pull__x__mongo={"list" : "listc"}) # Error
How can I pull from this list?
I appreciate any help
I believe that the problem is that mongoengine doesn't know the structure of your x document. You declared it as DictField, so mongoengine thinks you are pulling from DictField not from ListField. Declare x as ListField and both queries should work just fine.
I suggest you should also create an issue for this:
https://github.com/MongoEngine/mongoengine/issues
As a workaround, you can use a raw query:
Mydoc.objects(item_number=1).update_one(__raw__={'$pull': {'x.mongo': {'list': 'listc'}}})
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)
I use mongoengine for mongodb in django.
but.. mongoengine fields (like StringField) makes me build up schema toward the way that I don't want. I mean, it strictly insists that I pre-write key name before I do know what it will be. for example...
in case that I do not know what key name will be put into database...
> for(var i=0; i<10; i++){
... o = {};
... o[i.toString()] = i + 100;
... db.test.save(o)
... }
> db.test.find()
{ "_id" : ObjectId("4ed623aa45c8729573313811"), "0" : 100 }
{ "_id" : ObjectId("4ed623aa45c8729573313812"), "1" : 101 }
{ "_id" : ObjectId("4ed623aa45c8729573313813"), "2" : 102 }
{ "_id" : ObjectId("4ed623aa45c8729573313814"), "3" : 103 }
{ "_id" : ObjectId("4ed623aa45c8729573313815"), "4" : 104 }
{ "_id" : ObjectId("4ed623aa45c8729573313816"), "5" : 105 }
{ "_id" : ObjectId("4ed623aa45c8729573313817"), "6" : 106 }
{ "_id" : ObjectId("4ed623aa45c8729573313818"), "7" : 107 }
{ "_id" : ObjectId("4ed623aa45c8729573313819"), "8" : 108 }
{ "_id" : ObjectId("4ed623aa45c872957331381a"), "9" : 109 }
[addition]
as you can see above, key is very different from each other..
just assume that "I do not know what key name will be put into document as key ahead of time
as dcrosta replied.. I am looking for a way to use mongoengine without specifying the fields ahead of time.
[/addition]
How can I do the same thing through mongoengine?
please give me schema design like
class Test(Document):
tag = StringField(db_field='xxxx')
[addition]
I don't know what 'xxxx' will be as key name.
sorry.. I'm Korean so my english is awkward.
please give me your some knowledge.
Thanks for reading this.
[/addition]
Have you considered using PyMongo directly instead of using Mongoengine? Mongoengine is designed to declare and validate a schema for your documents, and provides many tools and conveniences around that. If your documents are going to vary, I'm not sure Mongoengine is the right choice for you.
If, however, you have some fields in common across all documents, and then each document has some set of fields specific to itself, you can use Mongoengine's DictField. The downside of this is that the keys will not be "top-level", for instance:
class UserThings(Document):
# you can look this document up by username
username = StringField()
# you can store whatever you want here
things = DictField()
dcrosta_things = UserThings(username='dcrosta')
dcrosta_things.things['foo'] = 'bar'
dcrosta_things.things['bad'] = 'quack'
dcrosta_things.save()
Results in a MongoDB document like:
{ _id: ObjectId(...),
_types: ["UserThings"],
_cls: "UserThings",
username: "dcrosta",
things: {
foo: "bar",
baz: "quack"
}
}
Edit: I should also note, there's work in progress on the development branch of Mongoengine for "dynamic" documents, where attributes on the Python document instances will be saved when the model is saved. See https://github.com/hmarr/mongoengine/pull/112 for details and history.