MongoEngine remove string from ListField - mongodb

code:
class Users(db.Document, UserMixin):
first_name = db.StringField()
last_name = db.StringField()
username = db.StringField(unique=True)
password = db.StringField()
email = db.StringField()
following = db.ListField(db.StringField(), default=[])
role = db.ListField(db.StringField(), default=["user"])
confirmed = db.BooleanField(default=False)
confirmed_on = db.DateTimeField()
so if I wanted to remove a certain string from the Users.following field
Users.objects(username="some_user").update(pull__following=["some_string"])
and then save it?
because I've tried this and it won't remove the string from the following listField

If you want to remove one element from your list you need to use the pull modifier which takes a single value not a list as you are doing so the correct query is:
Users.objects(username='some_user').update(pull__following='some_string')
You can also remove several element from your "following" list using the pull_all modifier; and in this case you pass in a list of value.
Users.objects(username='some_user').update(pull_all__following=['one_string', 'another_string'])

Related

How to query over a list of embedded documents with allow_inheritance

If I have the following schema:
class Post(EmbeddedDocument):
title = StringField(max_length=120, required=True)
meta = {'allow_inheritance': True}
class TextPost(Post):
content = StringField()
class MoviePost(Post):
author = ReferenceField(Authors)
class Record(Document):
posts = ListField(EmbeddedDocumentField(Post))
And I do the following query:
author = Author.objects.get_or_404(id = id)
records = Record.objects(posts__author = author)
records.count()
I get the following error:
AttributeError: 'author' object has no attribute 'get'
This seems to only happen with allow_inheritance when certain objects may or may not have the 'author' field. If the field exists on all objects, such as the 'title' field, the query works fine.
It seems that this is still an open issue in mongoengine that has yet to be addressed. One way around it is to use match. For example, the following does the trick:
records = Record.objects(posts__match = { 'author': author })

What is the correct way to UPDATE a document in an embedded list?

I am having some trouble finding a way to update, i.e. modify or delete a certain document in an embedded list. Here is my case:
CREATE CLASS Tag EXTENDS V
CREATE PROPERTY Tag.label STRING
CREATE CLASS Profession
CREATE PROPERTY Profession.jobtitle STRING
CREATE PROPERTY Profession.tags LINKSET Tag
CREATE CLASS UserProfile EXTENDS V
CREATE PROPERTY UserProfile.screenname STRING
CREATE PROPERTY UserProfile.profession EMBEDDEDLIST Profession
So, adding an entry to UserProfile.profession is no problem:
UPDATE UserProfile ADD profession =
{"#type":"d","#class":"Profession","jobtitle":"Actress", "tags" : ["#22:5"]}
WHERE screenname = 'emma'
Given some entry 'emma' for UserProfile and a Tag with id #22:5.
However, when I try to update the Profession-document with jobtitle 'Actress', how exactly should I proceed? I tried the following approach, which worked with but one entry in the list only:
UPDATE UserProfile SET profession =
{"#type":"d","#class":"Profession","jobtitle":"Actress", "tags" : ["#22:7", "#22:9"]}
WHERE profession.jobtitle = 'Actress'
AND screenname = 'emma'
This statement throws no exception and returns 0 as number of affected records.
In general: How do I access a specific entry (using a key of the document itself) in an embedded list or set to update or remove it?
Also: is there an easier way to update the tags linkset in the Profession-document in the embedded list? Or do I always have to get the whole document and write a modified version back?
Thanks!
Ingo
You can use
UPDATE UserProfile set profession = [{"#type":"d","#class":"Profession","jobtitle":"Actress", "tags" : ["#22:7", "#22:9"]}]
WHERE profession.jobtitle contains "Actress" AND screenname = 'emma'
UPDATE
You could use this javascript function
var g=orient.getGraph();
var b=g.command("sql","select from userprofile");
var tag1=g.command("sql","select from #22:7");
var tag2=g.command("sql","select from #22:9");
for(i=0;i<b.length;i++){
var screenname= b[i].getProperty("screenname");
if(screenname=="emma"){
var pro=b[i].getProperty("profession");
for(j=0;j<pro.length;j++){
if(pro[j].field("jobtitle")=="Actress"){
pro[j].field("tags",[tag1[0],tag2[0]]);
}
}
b[i].save();
}
}
try this
UPDATE UserProfile SET profession.jobtitle = 'aaaa'
WHERE profession.jobtitle = 'Actress'
AND screenname = 'emma'

PonyORM orphaned items when clearing a set that defines one-to-many relation

I have a basic relation defined as follows:
db = Database('sqlite', 'test_db.sqlite', create_db=True)
class WOEID(db.Entity):
woeid = PrimaryKey(int)
iso = Optional(str)
name = Required(str)
language = Optional(str)
place_type = Required(str)
parent_id = Required(int)
trends = Set('Trend')
ancestry = Optional(str)
class Trend(db.Entity):
woeid = Required(int)
events = Optional(str)
name = Required(str)
promoted_content = Optional(str)
query = Required(str)
url = Required(str)
location = Optional(WOEID)
db.generate_mapping(create_tables=True)
Now, I add some items to WOEID.trends within a function decorated with #db_session. This works as expected.
Now I try to update WOEID.trends by first reading an object using
location = WOEID.get(woeid = some_woeid)
later on I issue
location.trends.clear()
to delete old entries and I add new items to the trends set.
In the generated Trends table after this operation I have the items added, but previous items (cleared from the set) are not deleted, they stay in the database with 'location' field nulled (they are dereferenced I guess).
How should I perform the operation outlined above to get read of orphaned items?
There are two kinds of one-to-many relationships in PonyORM. The first kind of relationship is when one end of relationship is Set and the other end of relationship is Required. In that case when you remove an item from the collection this item will be deleted. For example we can define two entities Article and Comment in the following way:
class Article(db.Entity):
author = Required(User)
text = Required(str)
comments = Set('Comment')
class Comment(db.Entity):
author = Required(User)
text = Required(str)
article = Required(Article)
In that case, when you perform article.comments.clear() all comment will be deleted, because the Comment.article attribute is required and a comment cannot exist without an article.
The other kind of relationship is where Comment.article attribute is defined as Optional:
class Comment(db.Entity):
author = Required(User)
text = Required(str)
article = Optional(Article)
In that case a comment can exist without any article, and when you remove the comment from the Article.comments collection it remains in the database, but the Comment.article attribute value is set to NULL.
You can find orphaned items by executing the following query:
select(c for c in Comment if c.article is None)
or, equivalently
Comment.select(lambda c: c.article is None)
In some cases it may be desirable to define attribute as Optional, but perform cascade delete on removing item from the collection. In order to do this, you can specify cascade_delete option for the Set attribute:
class Article(db.Entity):
author = Required(User)
text = Required(str)
comments = Set('Comment', cascade_delete=True)
class Comment(db.Entity):
author = Required(User)
text = Required(str)
article = Optional(Article)
Then if you do article.comments.clear() then all removed comments will be deleted from the database.

Use SugarCRM Beans to retrieve data

I needed to convert this SQL query to bean format.
"SELECT first_name, last_name FROM leads INNER JOIN contacts_leads_1_c ON
leads.id=contacts_leads_1_c.contacts_leads_1leads_idb where
contacts_leads_1_c.contacts_leads_1contacts_ida='".$bean->id."'";
I have this already in place
$lead = new Lead();
$where = "contacts_leads_1_c.contacts_leads_1contacts_ida = '$bean->id' ";
$lead_list = $lead->get_full_list("", $where,true);
$all_leads = array();
foreach($all_leads as $leads){
$bean->contacts_leads = $ref->first_name . ',' . $ref->last_name;
This is the problem
$lead_list = $lead->get_full_list("", $where,true);
Thanks in advance,
If $bean is already a contact you can grab a list of the related fields:
$leads = $bean->get_linked_beans('FIELDNAME','Leads');
FIELDNAME can be found in the vardefs and isn't the relationship name it's the name of the field that defines the link.
Note: In your example you're creating an empty array then looping over it.

How can I use the same ObjectId for 2 collections using MongoEngine ReferenceField?

I have a fairly heavy User document class, and I would like to cut it in two pieces: the user's profile (name and avatar) in a UserProfile document and the rest in a User document, like this (using MongoEngine):
from mongoengine import *
class User(Document):
login = StringField()
password = StringField()
posts = ListField(ReferenceField("Post", dbref = False))
#... a bunch of other fields
class UserProfile(Document):
name = StringField()
avatar = URLField()
I would like to have the same ObjectId for both the UserProfile and the User, so that I only need one ObjectId to reference both the User and the UserProfile. After all, it's really a one-to-one relationship, and since a user can author many posts, I don't want to embed her profile in the posts themselves. When creating a user document, I would immediately create the corresponding profile document like this:
john = User.objects.create(login = "john", password = "super!password")
john_profile = UserProfile.objects.create(id = john.id, name = "John Smith",
avatar = "http://www.example.com/img/photo.jpg")
So far so good. Now I have a Post document with an author field that references the User document:
class Post(Document):
author = ReferenceField("User", dbref = False)
text = StringField()
I would like to add an author_profile reference, based on the same ObjectId. I tried this:
class Post(Document):
author = ReferenceField("User", dbref = False)
author_profile = ReferenceField("User", db_field = "author", dbref = False)
text = StringField()
But I get the following exception:
mongoengine.base.InvalidDocumentError: Multiple db_fields defined for: author
So it seems that I have to do so "manually". Something like this perhaps:
class Post(Document):
author = ReferenceField("User", dbref = False)
text = StringField()
#property
def author_profile(self):
if hasattr(self, "_author_profile"):
return self._author_profile
self._author_profile = UserProfile.objects.get(id = self._data["author"].id)
return self._author_profile
I guess it's not that bad, but isn't there a better solution?
Thanks.
Note: I read the mongodb documentation about one-to-one relationships, as well as the mongoengine ReferenceField documentation, but it did not help me on this specific question.
You'd have to store the same id twice to do this:
class Post(Document):
author = ReferenceField("User", dbref = False)
author_profile = ReferenceField("UserProfile", dbref = False)
text = StringField()
I'm not sure if that brings any benefits to your solution - there maybe an improvement in the number of queries to dereference, but I'd have to test that!
I ended up writing this:
def user_profile(reference_name):
attrib_name = "_" + reference_name + "_profile"
def user_profile_getter(self):
if not hasattr(self, attrib_name):
reference = self._data.get(reference_name, None)
if not reference:
return None
setattr(self, attrib_name, UserProfile.objects.get(reference.id))
return getattr(self, attrib_name)
return property(user_profile_getter)
My Post class now looks like this:
class Post(Document):
author = ReferenceField("User", dbref = False)
author_profile = user_profile("author")
text = StringField()
Whenever I add a ReferenceField that points to the User class, I also add such a user_profile (read-only) reference. Note that if you only access the author_profile, it will not load the author, and vice versa.