How to verify if a Neo4j Graph DB exist with Python? - python

I've this small snipped of code that load a file in an embedded Neo4j Database.
With this code I've two problems and I don't find documentation to solve it.
I'm following the samples of the documentation to create an index, but:
a) How can I detect if the index exists yet? The documentation explais that if the index already exists,
it's returned, but in my case it returns an error.
b) When I get the a node from the index I get an error
from neo4j import GraphDatabase, INCOMING, Evaluation
# Create a database
db = GraphDatabase("c:/temp/graph")
with db.transaction:
# Create an index for "users" nodes
# to look for them using some of the properties
# HERE I GET AN ERROR WHEN THE INDEX EXISTS PREVIOUSLY, BUT THE DOCUMENTATION EXPLAINS THE OPOSITE.
users_idx = db.node.indexes.create('users')
# Create the "users_reference" node to connect all "users" nodes to here
users_reference = db.node()
db.reference_node.USERS(users_reference, provider='lucene', type='fulltext')
'''
Content of the file
1,Marc
2,Didac
3,Sergi
4,David
'''
f = open("../files/users","r")
for line in f:
v = line.split(",")
i = v[0]
name = v[1]
# All write operations happen in a transaction
user = db.node(id=i, name=name)
user.INSTANCE_OF(users_reference)
users_idx['id'][i] = user
# I suppose that here, the transaction is closed
# I want get the node whose property "Id" has value "3"
# to print the property "name" of the node with id = 3
# HERE I GET AN ERROR WHEN THE THERE'RE MULTIPLE NODES WITH THE SAME VALUE FOR THE PROPERTY "ID"
c = users_idx['id']['3'].single
print c['name']
'''
If the file has a duplicated ID, the previouly code returns an error...
1,Marc
1,Marc_2
1,Marc_3
2,Didac
3,Sergi
4,David
'''
# Always shut down your database when your application exits
db.shutdown()

In your first example, the documentation is wrong. There is currently only one way to determine if an index exists, and it is to check for a ValueError when getting an index. Like this:
try:
idx = db.node.indexes.get('my_index')
except ValueError,e:
idx = db.node.indexes.create('my_index')
That should be changed to some more specific exception, since this pattern breaks if something else triggers a ValueError.. Will add an issue for that.
I've just pushed an update to the documentation, and I've added an "exists" method, to check if an index exists. It will be available on Pypi after the next neo4j milestone release.
if db.node.indexes.exists('my_index'):
db.node.indexes.get('my_index')
else:
db.node.indexes.create('my_index')
In your second example, I think this is correct behavior. The 'single' property assures that there is a single result. If you expect a single result, but get multiple, that is an error. If you want the first result, you should be able to do something like:
hits = iter(users_idx['id']['3'])
c = hits.next()
hits.close()

Related

How to open a document from a Notes View with python noteslib?

I have an established connection with a notes database and I am able to loop through all the records in a view. What I am curious about if it is possible to open a document and get the data from it using python. (Like double clicking on a record from an HCL Notes Client).
Here is my code simplified:
import noteslib
db = noteslib.Database('my-domino-server','my-db.nsf', 'mypassword')
view = db.GetView('my_view')
doc = view.GetFirstDocument()
while doc:
print(doc.ColumnValues)
#here after printing the column values, I want to open the document and store it's values in a variable.
doc = view.GetNextDocument(doc)
I tried googling about LotusScript and I found the Open() method, but doc.Open() did not work.
Just use the LotusScript documentation to find examples for everything you need.
In your case you start with the NotesDatabase - class, then get an object of type NotesView and finally get a NotesDocument object.
This doc object does not need to be opened. You can directly access all items in that document either by their name or -if you don't know the name- by cycling through all items.
If you e.g. know the name of an item (can be found in the document properties box on the second tab, found with Alt + Enter) then you can read the value like this:
#Subject of a given mail
subject = doc.GetitemValue( "Subject" )[0]
#Start date of a calendar entry
startdate = doc.GetItemValue( "StartDate" )[0]
# cycle through all items
for item in doc.Items
print(item.Name)
value = item.Values
Take care: items are always arrays, even if they contain only a single value. To get the value of a single value item, always access the element at position 0.

How to check if a key already exists in the database using Firebase and Python?

Essentially, I'll be using a database of this structure:
to keep track of the users' xp. Under the xp_data section, there will be multiple timestamps and xp numbers for each timestamp. A function will run every 24 hours, that will log the users' XP. I want to have some way to check if the player is already in the database (and if so, add to their existing xp count) and if not, create a new node for them. Here is my code for writing to the server:
db_ref = db.reference('/')
for i in range(100):
tom = await mee6API.levels.get_leaderboard_page(i)
if xp_trigger:
break
this_lb_list = {}
for l in tom['players']:
if l['xp'] < 300:
xp_trigger = True
break
this_lb_list.update({l['id']: {'name': l['username'], 'xp_data': {time.strftime(time_format_str, time.gmtime()): l['xp']}}})
details += [{ int(l['id']) : l['xp']}]
print(i)
db_ref.update(this_lb_list)
Basically, this code loops through each page in the leaderboard, obtains the XP for each user, and appends it to a dict, which is then used to update the database. there are two problems with this code, one is that it does not check if the user already exists, meaning that, and this is the second problem, that it overwrites the user's existing data. I've also attempted to write the data for each player individually, but problem 1 was still an issue, and it was painfully slow. What can I do to rectify this?
When you pass a value for a property in update(), that value replaces the entire existing value of the property in the database. So while update() leaves the properties you don't specify in the call unmodified, it does completely replace any property you do specify.
To add a value to an existing property, you'll want to specify the entire path as the key, separating the various child nodes with /.
So something like:
this_lb_list.update({'xp_data/13-Auth-2021': l['xp']})
This will write only the 13-Auth-2021 of xp_data, leaving all other child nodes of xp_data unmodified.
You'll of course want to use a variable for the date/time, but the important thing is that you specify it in the key, and not in the value of the dictionary.

Django - error from call to values_list: 'flat' is not defined

Here's a loop I'm using to process an Excel sheet with openpyxl. On occasion the partno field is missing and I try to derive it from another database table (booking) using a field called transmittal. I'm having trouble with this lookup and it returns an error. When I run the same thing under the Django shell, it works fine.
parser = parse_defrev(book)
brs = []
xmtl_part = {}
invalid = []
for r in parser.process():
# If no partno, try to look it up in the bookings table
if r.get('partno') is None:
xmtl = r.get('transmittal')
if xmtl:
r['partno'] = xmtl_part.get(xmtl)
if not r['partno']:
parts = set(Booking.objects.filter(bookingtransmittal=r['transmittal']).values_list('bookingpartno', flat=True))
if len(parts) == 1:
r['partno'] = parts.pop()
xmtl_part[xmtl] = r['partno']
process is a generator function in the parse_defrev class which returns a dictionary with the processed fields from the workbook. If partno is missing, then it first tries to retrieve it from a caching dictionary and then from the booking table. The values_list returns any matching partno values, and if there is more than 1 match it just logs the problem and skips to the next row.
I get the following error, and don't understand how it could fail to recognize the flat keyword.
parts = set(Booking.objects.filter(bookingtransmittal=r['transmittal']).values_list('bookingpartno', flat=True))
NameError: name 'flat' is not defined
However it works in the Django shell, after importing Booking, I do this.
>>> r = dict()
>>> r['transmittal'] = '21/05 01'
>>> parts = set(Booking.objects.filter(bookingtransmittal=r['transmittal']).values_list('bookingpartno', flat=True))
& irrespective of whether there are zero or more fields in the lookup result, it returns the expected result, which is a set containing the part numbers.
Python 3.9.5, Django 3.2.4, Windows client under Visual Studio Code with git bash shell, to CentOS PostgreSQL back end.
There's an easy workaround, which is a simple change, but I'd still like to understand why the flat keyword isn't recognized here.
parts = set(Booking.objects.filter(bookingtransmittal=r['transmittal']).values_list('bookingpartno'))
if len(parts) == 1:
r['partno'] = parts.pop()[0]

Getting element density from abaqus output database using python scripting

I'm trying to get the element density from the abaqus output database. I know you can request a field output for the volume using 'EVOL', is something similar possible for the density?
I'm afraid it's not because of this: Getting element mass in Abaqus postprocessor
What would be the most efficient way to get the density? Look for every element in which section set it is?
Found a solution, I don't know if it's the fastest but it works:
odb_file_path=r'your_path\file.odb'
odb = session.openOdb(name=odb_file_path)
instance = odb.rootAssembly.instances['MY_PART']
material_name = instance.elements[0].sectionCategory.name[8:-2]
density=odb.materials[material_name].density.table[0][0])
note: the 'name' attribute will give you a string like, 'solid MATERIALNAME'. So I just cut out the part of the string that gave me the real material name. So it's the sectionCategory attribute of an OdbElementObject that is the answer.
EDIT: This doesn't seem to work after all, it turns out that it gives all elements the same material name, being the name of the first material.
The properties are associated something like this:
sectionAssignment connects section to set
set is the container for element
section connects sectionAssignment to material
instance is connected to part (could be from a part from another model)
part is connected to model
model is connected to section
Use the .inp or .cae file if you can. The following gets it from an opened cae file. To thoroughly get elements from materials, you would do something like the following, assuming you're starting your search in rootAssembly.instances:
Find the parts which the instances were created from.
Find the models which contain these parts.
Look for all sections with material_name in these parts, and store all the sectionNames associated with this section
Look for all sectionAssignments which references these sectionNames
Under each of these sectionAssignments, there is an associated region object which has the name (as a string) of an elementSet and the name of a part. Get all the elements from this elementSet in this part.
Cleanup:
Use the Python set object to remove any multiple references to the same element.
Multiply the number of elements in this set by the number of identical part instances that refer to this material in rootAssembly.
E.g., for some cae model variable called model:
model_part_repeats = {}
model_part_elemLabels = {}
for instance in model.rootAssembly.instances.values():
p = instance.part.name
m = instance.part.modelName
try:
model_part_repeats[(m, p)] += 1
continue
except KeyError:
model_part_repeats[(m, p)] = 1
# Get all sections in model
sectionNames = []
for s in mdb.models[m].sections.values():
if s.material == material_name: # material_name is already known
# This is a valid section - search for section assignments
# in part for this section, and then the associated set
sectionNames.append(s.name)
if sectionNames:
labels = []
for sa in mdb.models[m].parts[p].sectionAssignments:
if sa.sectionName in sectionNames:
eset = sa.region[0]
labels = labels + [e.label for e in mdb.models[m].parts[p].sets[eset].elements]
labels = list(set(labels))
model_part_elemLabels[(m,p)] = labels
else:
model_part_elemLabels[(m,p)] = []
num_elements_with_material = sum([model_part_repeats[k]*len(model_part_elemLabels[k]) for k in model_part_repeats])
Finally, grab the material density associated with material_name then multiply it by num_elements_with_material.
Of course, this method will be extremely slow for larger models, and it is more advisable to use string techniques on the .inp file for faster performance.

Implementing 'delete' method syntax (and set)

I'm writing my first Python class and I was wondering if this was correct syntax to remove a particular 'song' from my dictionary.
I load data from a file onto a dictionary and store it.
Is this syntax correct?
def delete_song(id): #Do I need to do self_song(self, id) instead?
del self.song_names[id]
id is the song's ID, which is being passed. Does this delete a song from my dictionary? Earlier on in the code I had saved a song's name to self.song_names[id]= sname, which was from a component sname=components[1] from reading in the file.
Also, I'm having trouble understanding how to go about the set function. Is this start on the right track?
def set_song(id, list((title,genres))):
self.movie_names[id] = title
self.movie_genres[id] = genres
I figured out how to implement the get method and in it I use
self.song_names[id] = sname and
self.song_genres[id] = sgenre
Any tips?
You should read a chapter on classes here.
And, for deleting an entry from a dictionary, it is safer to use pop:
self.song_names.pop(id, None) <--- will not raise an error if id is not found
del self.song_names[id] <--- raises KeyError if id not found

Categories