rbw / pysnow

ServiceNow API Client Library
MIT License
204 stars 90 forks source link

How to solve pysnow.exceptions.MultipleResults #120

Closed aufbakanleitung closed 5 years ago

aufbakanleitung commented 5 years ago

Hi,

I have a PySnow script that searches for users based on their e-mail address:

def get_caller(email):
    incident = c.resource(api_path='/table/sys_user')
    incidents = incident.get(query={"email": email})
    try:
        response = incidents.one()
    except pysnow.exceptions.MultipleResults:
        response = incidents[0]
    except pysnow.exceptions.NoResults:
        response = find_caller_by_old_email(email)
    return response

However for some users there are two active records with the same e-mail in the ServiceNow database. two active B-id's

While this is something that shouldn't happen, it's nevertheless something I have to deal with. Else I get the following error:

(....)
  File "/Users/hermanvanderveer/anaconda3/lib/python3.6/site-packages/pysnow/response.py", line 45, in __getitem__
    return self.one().get(key)
  File "/Users/hermanvanderveer/anaconda3/lib/python3.6/site-packages/pysnow/response.py", line 213, in one
    raise MultipleResults("Expected single-record result, got multiple")
pysnow.exceptions.MultipleResults: Expected single-record result, got multiple

I've tried several options to fix this. incidents[0] didn't work, nor did incidents.first() which throws an error like first() only works when stream=true.

Also I would prefer if I could get the user with the highest B-number or latest creation date or something. How can I fix this?

rbw commented 5 years ago

Try this:

users = c.resource(api_path='/table/sys_user')
result = users.get(query={"email": email}, stream=True).first_or_none()

That'd give you the first record (of many, potentially) or None if no matches were found. Replace first_or_none() with first() if you want the NoResults thrown if there are no matches.

Also I would prefer if I could get the user with the highest B-number or latest creation date or something. How can I fix this?

Something like this perhaps?:

query = (
    pysnow.QueryBuilder()
    .field("email").equals(email)
    .AND()
    .field("sys_created_on").order_descending()
)
users = c.resource(api_path='/table/sys_user')
result = users.get(query=query, limit=1).one_or_none()  # Use one() to raise NoResults
aufbakanleitung commented 5 years ago

Thanks!

That fixed it, and my code is a lot cleaner now ^^

def get_caller(email):
    users = c.resource(api_path='/table/sys_user')
    try:
        result = users.get(query={"email": email}, stream=True).first()
    except pysnow.exceptions.NoResults:
        result = find_caller_by_old_email(email)
    return result

def find_caller_by_old_email(email):
    users = c.resource(api_path='/table/sys_user')
    result = users.get(query={"u_old_email": email}, stream=True).first_or_none()
    return result

It seems it automatically picks the newest user already :D