I did some streamlining to your query… some of your issues are caused by how the default inputset ._ is used and overwritten. To make things clearer, I switched to named inputsets where possible.
So, here’s a list of all changes:
use a global bounding box instead of repeatingly adding ({{bbox}})
Named inputsets are empty by default, no need to initialize them
move the building query outside the foreach loop, store it in an inputset and use the inputset inside the foreach loop instead
added [“addr:street”] restriction to building query, assuming you’re only interested in buildings with such a tag (performance)
avoid unnecessary sets where possible
add [name] restriction to highway=residential (performance)
use named inputsets for foreach statement, dont’t realy on ._ , i.e. no need to fiddle around with ._ and store it in a named inputset only inside the loop.
resolving ways to nodes is done only towards the end of the query (it’s not needed earlier than that)
And the updated query:
//This query gets residentials and their buildings within bbox.
[out:json][timeout:25]
[bbox:{{bbox}}]; // set global bounding box
// retrieve all residential ways with name
way[highway=residential][name] ->.highways;
// retreve buildings outside the foreach loop (performance)
( way[building]["addr:street"];
rel[building]["addr:street"];
) -> .allbuildings;
foreach.highways -> .a (
// find buildings where addr:street matches highway name
(
way.allbuildings (if: t["addr:street"] == a.set(t["name"]));
relation.allbuildings (if: t["addr:street"] == a.set(t["name"]));
)-> .buildings;
// collect building
(.result_buildings; .buildings; )->.result_buildings;
);
// resolve ways to nodes
( ( .result_buildings; .highways;); >;);
// return result
out;
You can think of an inputset (named or .) as some kind of global variable, which is valid for the whole query. Once you assign some data to it, it will keep it for the rest of the query. If you assign some other data to an inputset, the previous contents will be replaced. Note that some queries / statements will change the contents of the default inputset ".", which can be confusing at times. If you’re unsure, use named inputsets instead, like in my example.
If it’s not mentioned in the Overpass QL documentation there’s probably no dedicated document. Usually you would find the respective information for each statement, like union, or foreach.
Yes, that’s due to the way how ways are resolved to nodes. The approach I used is more suitable for editing in JOSM, as it includes all data (out meta; instead of out; would still be better). If you don’t want to this level of detail, you could use either http://overpass-turbo.eu/s/q0a or http://overpass-turbo.eu/s/q0f
Well, that was my intuition at the beginning (one of things I tried before posting here was switching to .nodeless set instead of ._).
OK, so just to see if I understand it correctly, I’ve changed the original query to: http://overpass-turbo.eu/s/q42
It uses named set .nodeless instead of ._ , does not initiate .result set and tries to collect buildings directly into .result inside foreach loop. Could you pinpoint why this query does not return any buildings? I know your query is better, but I want to understand what I’m doing.
foreach iterates over all entries in the default set ._. At this time it contains a number residential ways, which is in fact a side effect of an earlier way"highway"=“residential”; inside a union statement.
Now, (.nodeless;) → .a; is basically just copying ALL residential ways from .nodeless to .a - that’s not really what you want, especially, as the copying occurs in every single foreach iteration. What you’re really after is to take one element from .nodeless and store it in .a.
Going further, a.set(t[“name”]) will produce a concatenated list of ALL names - check the output of this debug query: http://overpass-turbo.eu/s/q5G
Iterating over a named inputset and assigning one element per each iteration has a different syntax: