Alternative for FindFirstChild for nested instances

Hello
In some cases I would like to reach a nested instance - for example Main.Model1.Model2.Part3
But I would like, if any of the instances in the path does not exist, to not trigger an error but the whole expression to return nil.

If I do Main:FindFirstChild(“Model1”):FindFirstChild(“Model2”) this will trigger an error if Model1 does not exist.
Is there some built-in expression which can be used or I have to make my own function?

Thanks in advance

FindFirstChild(name, true) takes a second parameter for recursive search.

This is not what I need.
I need to browse a specific Path, not to search all descendants for matching name.

Oh, I see what you mean, though you meant any instance with the given name. You will need your own function. Here’s one that requires a path as a string and a place to begin the search at. Currently it works with alphanumeric names but the pattern can be adjusted.

local function FindInstanceByPath(path: string, place: Instance): Instance?
	local current = place
	for level in string.gmatch(path, "%w+") do
		current = current:FindFirstChild(level)
		if not current then
			return nil
		end
	end
	return current
end

-- Test with an instance path A.B.C in workspace:
print(FindInstanceByPath("A.B", workspace)) --> B
print(FindInstanceByPath("A.B.C", workspace)) --> C
print(FindInstanceByPath("A.B.D", workspace)) --> nil
print(FindInstanceByPath("A.E", workspace)) --> nil

Edit.

Splitting the string works fine too (haven’t benchmarked the performance difference). I believe gmatch is more flexible in this case.

To allow whitespace in names you can build character sets like [%w%s]+ etc.

Edit 2.

@mooonc0w that’s right, thank you for noticing the typo, I corrected it.

1 Like

“current” should be equal to “place”, not to “workspace”?

local function findNested(start: Instance, sequence: string): Instance?
	local current = start
	for _, name in pairs(sequence:split(".")) do
		current = current:FindFirstChild(name)
		if not current then return nil end
	end
	return current
end

local model2 = findNested(Main, "Model1.Model2")

if model2 then
	print("Model2 found:", model2)
else
	print("Model2 not found")
end
1 Like

PCalls could work for your situation.

You would run the referencing code in a PCall function, and if the function returns an error, you could set whatever variable you’re talking about to nil. If its a success, then you can run whatever code you planned on running.

local Success, Error = pcall(function()
    Reference = workspace.Baseplate.SomethingThatDoesntExist
end)

if Success then
	print("it exists!")
else
	print("it doesnt exist!")
	Reference = nil
end


print(Reference)

image

1 Like

FindFirstChild recursive should be your solution, it should return nil by default if it doesn’t exist. If you only want to search for the child that is inside of Model2, you can check for the parent of the child.

I’m following up the original reply with a better function that takes a tuple of names consisting of any sort of characters, including the ones with emojis, whitespaces, additional dots etc… Those cases are hard to handle with string.split or string.gmatch. And it is 30% faster.

local function BetterFindInstanceByPath(place: Instance, ...: string | number): Instance?
	local current = place
	for i, level in {...} do
		current = current:FindFirstChild(level)
		if not current then return nil end
	end
	return current
end
print(BetterFindInstanceByPath(workspace, "A", "B", "C")) --> "C"

pcall looks promising because of the simplicity, except protected calls are a bit slower.

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.