如何使用AutoDesk Forge Viewer同时搜索元素的Level与Category属性?
Great question! The out-of-the-box viewer.search() method doesn't directly support simultaneous exact matches across multiple different properties (like matching both a specific Level value and a specific Category value at the same time) — the default behavior, when you pass an array of attributes, will match elements where any of those attributes contains your search text, not all of them with distinct values.
But don't worry, there are two reliable workarounds to build this multi-condition search:
Workaround 1: Filter Search Results in the Callback
First, use viewer.search() to get all elements matching one of your target properties (e.g., the Level value), then filter those results to keep only elements that also match your second property (e.g., the Category value).
To handle the async nature of property fetching, use Promise.all to ensure all checks complete before running your final callback:
const targetLevel = "Level 1"; // Replace with your desired Level value const targetCategory = "Walls"; // Replace with your desired Category value const yourCallback = (matchingDbIds) => { // Your custom logic for handling matching elements console.log("Elements matching both Level and Category:", matchingDbIds); }; // Step 1: Search for elements with the target Level viewer.search(targetLevel, async (initialDbIds) => { const matchingDbIds = []; // Step 2: Check each result's Category property await Promise.all(initialDbIds.map(dbId => { return new Promise(resolve => { viewer.getProperties(dbId, (props) => { // Find the Category property in the element's property list const categoryProp = props.properties.find(p => p.displayName === "Category"); if (categoryProp && categoryProp.displayValue === targetCategory) { matchingDbIds.push(dbId); } resolve(); }); }); })); // Step 3: Pass final results to your callback yourCallback(matchingDbIds); }, null, ["Level"]); // Restrict initial search to only the "Level" attribute
Workaround 2: Directly Query the Property Database
For better performance (especially with large models), skip the initial viewer.search() and query the model's property database directly. This avoids redundant searches and lets you check both properties in a single pass:
const targetLevel = "Level 1"; const targetCategory = "Walls"; const yourCallback = (matchingDbIds) => { console.log("Elements matching both Level and Category:", matchingDbIds); }; const model = viewer.model; const propDb = model.getPropertyDb(); const matchingDbIds = []; // Traverse all elements and check both properties propDb.executeUserFunction((dbId) => { // Get the Level property value const levelProp = propDb.getObjectProperty(dbId, "Level"); if (levelProp?.displayValue === targetLevel) { // Get the Category property value const categoryProp = propDb.getObjectProperty(dbId, "Category"); if (categoryProp?.displayValue === targetCategory) { matchingDbIds.push(dbId); } } }); // Pass results to your callback yourCallback(matchingDbIds);
Key Note
The native viewer.search() is designed for fuzzy text matching across one or more attributes, but it doesn't support logical AND conditions for distinct property values. The above workarounds fill that gap by either post-filtering search results or directly accessing the underlying property data.
内容的提问来源于stack exchange,提问作者stonecompass

