Mongoengine String Field in List field make unique - mongoengine

I use mongoengine and flask-restplus for API Server.
My model is here.
from datetime import datetime
from mongoengine import *
from config import DB_NAME
connect(DB_NAME)
class Board(Document):
d = datetime.now()
date = "{}-{}-{}".format(d.year, d.month, d.day)
no = SequenceField()
title = StringField(required=True)
body = StringField(required=True)
tags = ListField(StringField(unique=True))
password = StringField(required=True)
created_at = DateTimeField(default=date)
updated_at = DateTimeField(default=date)
I defined tags = ListField(StringField(unique=True)).
Because article can't got duplicated tag.
Insert tag code is here.
tag = ~some user input here~
article = Board.objects.get(no=article_no)
article.tags.append(tag)
article.save()
But when I insert the duplicated data, it stored data twice.
I want to tags has distinct data.
Why unique=True doesn't work?
Is there any solution about this issue?

Here's an explanation why does it not work. As a workaround you could use $addToSet operator provided by Mongo. It is also implemented in Mongoengine(docs) and an example usage would look like this
Board.objects(no=article_no).update_one(add_to_set__tags=tag)
where tag can be string or list of strings

Related

How to handle foreign-keys during the iteration through attributes of Django model (Python)?

Dear Django/Python experts. I have a Django model (python class) which contain standard fields and also fields represented by foreign keys. It is easy to iterate throught attributes of a model however I have no idea how to handle foreign keys?
Here is a model nr.1 Employee containing foreign key which refers to another model EmployeeLocation:
class Employee(models.Model):
firstname = models.CharField(max_length=128)
lastname = models.CharField(max_length=128)
location = models.ForeignKey(EmployeeLocation, on_delete=models.CASCADE)
and here is a model nr.2 EmployeeLocation:
class EmployeeLocation(models.Model):
id = models.BinaryField(primary_key=True, max_length=16, null=False)
city = models.CharField(max_length=32)
and now I iterate via attributes of Employee in the following way:
# Collecting names of class fields.
field_names = [f.name for f in Employee._meta.get_fields()]
for current_attribute in field_names:
field_value = str(getattr(my_employee, current_attribute))
This solution works fine for standard attributes but does not return values when reaches the location which is a foreign key.
To tackle this issue I did the following stunts :) :
I have made a dictionary containing names of foreign keys and as values I have placed Django queryset, that gets a value - but this is not an elegant hack :) In this way then iteration ecounters attribute which is foreign-key, it takes value from dictionary (which is generated by queryset):
FKs = {'location': EmployeeLocation.objects.filter(id=my_employee.location_id)[0].city,
...
...}
# Collecting names of class fields.
field_names = [f.name for f in Employee._meta.get_fields()]
for current_attribute in field_names:
if current_attribute in FKs.keys():
field_value = FKs[current_attribute]
else:
field_value = str(getattr(my_employee, current_attribute))
Please tell me in simple way how shall I realize it properly. Thank you so much in advance :)

Checking for the existence of objects with certain fields in pymongo

I need to check if an object exists in the database that has at least one matching field with a field from the dictionary
Pymongo
I have this, but it doesn't work:
import pymongo
client = pymongo.MongoClient()
users_db = client['UsersDB']
users_collection = users_db['users']
def check(collection, elements):
return bool(collection.find_one(filter={'$or' : [item for item in elements.items()]}))
You are on the right track but the query needs to be valid MQL. Try:
collection.find_one(filter={'$or' : [{k:{'$eq':v}} for k,v in elements.items()]})

How to know what collections I have in Firestore using Python API

I am using Python to conect to a firestore database from a client.
The problem is that I don't know how to see what collections he has in the database:
from google.cloud import firestore
import firebase_admin
from firebase_admin import credentials
from firebase_admin import firestore
cred = credentials.Certificate('credentials/credentials.json')
app = firebase_admin.initialize_app(cred)
db = firestore.client()
users_ref = db.collection(u'name_of_colection')
docs = users_ref.stream()
for doc in docs:
print(u'{} => {}'.format(doc.id, doc.to_dict()))
I have been looking how to get the name of the collections that he has but I didn't find anything that it was useful to me. I have also tried this:
cols = db.collections()
list_col = []
for col in cols:
list_col.append(col)
len(list_col)
I have obtained len = 6
Then I have done this for the different col in the list I have generated:
docs = list_col[5].stream()
data = []
for doc in docs:
data.append(doc.to_dict())
print(data)
This data print a dictionary with keys and values, but I don't know only get a list with the name of collections,
I think that you have to get the id from each collection (which is the collection name you are talking about
list_col = []
for col in collections:
list_col.append(col.id) // <-- add this please
print(list_col)
I hope it helps you
Any collection you see in fire base depends on your rights.
you can use
query = client.collection_group('mygroup')
or
query = client.collections()
It gives top hierarchy and you have to run multiple times to find the lowest document level.
query = client.collection_group('mygroup')
#param {string} collectionId Identifies the collections to query over. Every collection or subcollection with this ID as the last segment of its path will be included. Cannot contain a slash. #returns {Query} The created Query.
collections()[source]
List top-level collections of the client’s database.
Returns
iterator of subcollections of the current document.
Return type
Sequence[CollectionReference]
Simple solution:
import firebase_admin
from firebase_admin import firestore
app_options = {'projectId': 'test-project'}
default_app = firebase_admin.initialize_app(options=app_options)
db = firestore.client()
collection = db.collections()
list_col = []
for col in collection:
list_col.append(col.id)
print(list_col)

MongoEngine: How to append document to ListField

I'm using mongodb with python.
Also use MongoEngine to communicate with mongodb.
Now I made some simple board system that has comment function.
[model.py]
import datetime
from mongoengine import *
from config import DB_NAME
connect(DB_NAME)
class User(Document):
no = SequenceField()
userid = StringField(unique=True, required=True)
userpw = StringField(required=True)
created_at = DateTimeField(default=datetime.datetime.now())
class Comment(EmbeddedDocument):
content = StringField(required=True)
writer = ReferenceField(User, required=True)
class Board(Document):
no = SequenceField()
subject = StringField(required=True)
content = StringField(required=True)
writer = ReferenceField(User, required=True)
comments = ListField(EmbeddedDocumentField(Comment))
created_at = DateTimeField(default=datetime.datetime.now())
updated_at = DateTimeField(default=datetime.datetime.now())
In this code, How can I append new list to Board's comments field?
After searching for a hour, some document says that,
Board.objects(no=_no).update_one(push__comments=['123', '456']) will be works perfectly.
But it throw mongoengine.errors.InvalidQueryError: Querying the embedded document 'Comment' failed, due to an invalid query value error.
Maybe there is some syntax error, But I'm new at MongoEngine.
How can I solve this issue?
Thanks.
[SOLVED]
comment = Comments(content='test', writer='hide')
board = Board.objects(no=_no).get()
board.comments.append(comment)
board.save()
I solved issue like this.
But, if is there any solution, please comment it.
You can also use push operator https://docs.mongoengine.org/guide/querying.html?highlight=operators#atomic-updates

Mongoengine Link to Existing Collection

I'm working with Flask/Mongoengine-MongoDB for my latest web application.
I'm familiar with Pymongo, but I'm new to object-document mappers like Mongoengine.
I have a database and collection set up already, and I basically just want to query it and return the corresponding object. Here's a look at my models.py...
from app import db
# ----------------------------------------
# Taking steps towards a working backend.
# ----------------------------------------
class Property(db.Document):
# Document variables.
total_annual_rates = db.IntField()
land_value = db.IntField()
land_area = db.IntField()
assessment_number = db.StringField(max_length=255, required=True)
address = db.StringField(max_length=255, required=True)
current_capital_value = db.IntField
valuation_as_at_date = db.StringField(max_length=255, required=True)
legal_description = db.StringField(max_length=255, required=True)
capital_value = db.IntField()
annual_value = db.StringField(max_length=255, required=True)
certificate_of_title_number = db.StringField(max_length=255, required=True)
def __repr__(self):
return address
def get_property_from_db(self, query_string):
if not query_string:
raise ValueError()
# Ultra-simple search for the moment.
properties_found = Property.objects(address=query_string)
return properties_found[0]
The error I get is as follows: IndexError: no such item for Cursor instance
This makes complete sense, since the object isn't pointing at any collection. Despite trolling through the docs for a while, I still have no idea how to do this.
Do any of you know how I could appropriately link up my Property class to my already extant database and collection?
The way to link a class to an existing collection can be accomplished as such, using meta:
class Person(db.DynamicDocument):
# Meta variables.
meta = {
'collection': 'properties'
}
# Document variables.
name = db.StringField()
age = db.IntField()
Then, when using the class object, one can actually make use of this functionality as might be expected with MongoEngine:
desired_documents = Person.objects(name="John Smith")
john = desired_documents[0]
Or something similar :) Hope this helps!
I was googling this same question and i noticed the answer has changed since the previous answer:
According to the latest Mongoengine guide:
If you need to change the name of the collection (e.g. to use MongoEngine with an existing
database), then create a class dictionary attribute called meta on your document, and set collection to the
name of the collection that you want your document class to use:
class Page(Document):
meta = {'collection': 'cmsPage'}
The code on the grey did the trick and i could use my data instantly.

Resources