Notebook update all features?

868
11
Jump to solution
02-02-2023 11:18 AM
DamonBreen
New Contributor III

All,

I'm creating my first notebook, and following a guide on adding new features I found online. Modeling after that a bit, I think I'm most of the way there, but i'm missing something. I'm not a programmer, I just learn things as I have a need, so please keep that in mind. 

I have an inspection map that has over a thousand features, and some of these features need to be inspected once a month, others every 6 months, and others once a year. For right now, I am dealing with a dataset that has 4 features in it to test functionality. These get inspected once a month, and the field user updates a field to keep track of the features inspections. I'd like these to reset each month automatically. Here is what I have so far:

item = gis.content.get("7e781f27da1a4c9f9967a777910383fd")
RectifierLayer = item.layers[3]
UpdatedStatus = "Not Completed"
RectifierDict = {"attributes": {"Completed": UpdatedStatus}}
UpdateRectifier = RectifierLayer.edit_features(updates=[RectifierDict])
print(UpdateRectifier)

and here is the result I am getting

{'addResults': [], 'updateResults': [{'objectId': -1, 'globalId': None, 'success': False, 'error': {'code': 1000, 'description': 'Must declare the scalar variable "@OBJECTID".'}}], 'deleteResults': []}

My assumption is that since I followed a tutorial on adding a new feature, and I am trying to edit an existing one, I need to specify which feature to update, but I want to update one field in all features. Maybe I am wrong on that. I know the item ID is correct, the layer number is correct, and I think most of the syntax is correct. I have a lot of uses for notebooks, and have always been intimidated by creating them, but needed a simple task to get involved with them. I appreciate any input I will get. Thanks !

0 Kudos
1 Solution

Accepted Solutions
jcarlson
MVP Esteemed Contributor

Your RectifierDict isn't a valid object to submit as an update object. Properly formatted, this would have a dict of attributes for every feature.

If you just want to update a single field for all features, use the calculate method.

RectifierLayer.calculate(
    where='1=1',
    calc_expression={"field": "Completed", "value" : "Not Completed"}
)
- Josh Carlson
Kendall County GIS

View solution in original post

0 Kudos
11 Replies
jcarlson
MVP Esteemed Contributor

Your RectifierDict isn't a valid object to submit as an update object. Properly formatted, this would have a dict of attributes for every feature.

If you just want to update a single field for all features, use the calculate method.

RectifierLayer.calculate(
    where='1=1',
    calc_expression={"field": "Completed", "value" : "Not Completed"}
)
- Josh Carlson
Kendall County GIS
0 Kudos
DamonBreen
New Contributor III

This seems like it's what I want, but when I run it, it gives me an error code that that's an invalid field:

Exception: Unable to calculate fields.
'calcExpression' parameter is invalid
Invalid field name.
(Error Code: 400)

 

 

RectifierLayer.calculate(
    where='1=1',
    calc_expression={"field": "Completed", "value" : "Not Completed"}
)

 



I know that that is the correct field name. It is not the display name, but the field name. Caps-sensitive and all. Any ideas?

 

0 Kudos
jcarlson
MVP Esteemed Contributor

Ah, right! The expression needs to be a SQL expression. "Not", it understands, but "Completed", less so.

Replace the value part of the calc_expression with this:

"'Not Completed'"
- Josh Carlson
Kendall County GIS
0 Kudos
DamonBreen
New Contributor III

I did that, and I still have the same error. It seems to have a problem with the field name ("Completed") and not the value being input ("'Not Completed'")

0 Kudos
jcarlson
MVP Esteemed Contributor

Well, the way the initial one was written, it was telling the server to submit the SQL expression "Not Complete", which would attempt to interpret Complete as a field name. So it sounded like maybe the issue with the field name might have been there. "'Not Complete'" on the other hand, is a single string value, so the server would understand it differently.

You could try querying the whole layer to a dataframe, update the value there, and push it back to the service. Does this work?

df = RectifierLayer.query(
    out_fields = ['objectid', 'Completed'],
    as_df = True
)

df['Completed'] = 'Not Completed'

RectifierLayer.edit_features(updates=df.spatial.to_featureset())

 

- Josh Carlson
Kendall County GIS
0 Kudos
DamonBreen
New Contributor III
Exception: Cannot perform query. Invalid query parameters.
Unable to perform query. Please check your parameters.
(Error Code: 400)

It seems to really not like cooperating with this feature layer apparently. I may try with a different feature layer tomorrow and see if I get somewhere with it. This stuff is so frustrating some times. I appreciate your help with it though
0 Kudos
jcarlson
MVP Esteemed Contributor

Odd. Well, now I'm curious!

If you do [print(f) for f in RectifierLayer.properties['fields']] what does the output look like? It sounds like that isn't the field name, but if it is, then you may want to look at the service settings. It almost sounds like the query capability isn't turned on.

- Josh Carlson
Kendall County GIS
0 Kudos
DamonBreen
New Contributor III

So we made some changes to this map this year, and I just created a second notebook to look at the item ID of last years version of this map. Everything pertaining to the rectifier layer is exactly as it is in this years version of the map. I went through the services directory and compared the layers side by side and I see no difference. But the second notebook I made to update last years works perfectly. For that, I am going to go ahead and accept the answer as the solution. 

 

I just went back to input that last bit of code that you had suggested, and noticed something odd myself. In the service directory for the layer we have been trying to get this to work on, it says that the rectifier layer is id:3, but there is no id:0 like I have seen on other maps. see pictures of the service directory for both feature layers:

DamonBreen_0-1675372528300.pngDamonBreen_1-1675372566618.png

So instead of referencing id 3 in my notebook, I changed it to id 2 and it worked. The notebook compiled, and the map updated. Why is that do you think? It almost seems like a layer was deleted from the feature service. I didn't make this map, and the new guy that I trained did, so it's a bit hard telling what he may have done haha.

0 Kudos
jcarlson
MVP Esteemed Contributor

Interesting. I know in later versions of Portal, it's possible to assign unique layer ids to prevent layers from republishing things out of order by mistake. But I also know that other "layers" in the service (relationship classes, for example) can be assigned a number, but as they are not feature services, they aren't exposed in the REST endpoint.

As far as the 2 / 3 issue, that one is easy. FeatureLayer.layers returns a list, and you're just grabbing item x in the list when you access FeatureLayer.layers[x]. So the number doesn't actually matter in the REST directory.

FeatureLayer.tables works the same way. I have lots of layers with a standalone table in them that relate into the geometry. A table might be at the layer index of 5, but if it's the first table in the service, it will be at the list index of 0 when I call FeatureLayer.tables.

- Josh Carlson
Kendall County GIS
0 Kudos