如何在Magnolia中创建跨双仓库查询,定位已发布但所在页面未发布的资产?
解决Magnolia跨仓库查询已发布但无已发布页面引用的资产问题
你遇到的问题确实是Magnolia + JCR的典型限制:JCR本身不支持跨Workspace(也就是Magnolia里的“仓库”)执行SQL2或XPath查询,所以直接用UNION、JOIN这类SQL语法肯定行不通。不过我们可以通过分查询+应用层关联或者利用Magnolia的内置API来解决这个需求,下面是几个可行的方案:
方案1:分两次查询+代码层关联(最直接)
这个思路是先分别从两个仓库获取数据,再在代码里做对比筛选,适合快速实现或者用Groovy控制台临时查询。
步骤分解:
- 从dam仓库获取所有已发布的目标资产
用你原来的JCR-SQL2查询即可,拿到所有符合路径条件且已发布的资产。 - 从website仓库获取所有已发布页面引用的资产ID/路径
遍历所有已发布页面,提取它们引用的资产标识(可能是UUID或dam路径)。 - 对比筛选出“已发布但未被任何已发布页面引用”的资产
Groovy脚本示例(可在Magnolia Groovy控制台执行)
// 1. 获取dam仓库会话并查询已发布资产 def damSession = MgnlContext.getJCRSession('dam') def publishedAssetsQuery = """ select p.* from [mgnl:asset] as p where (ISDESCENDANTNODE('/demo-features/tests') or ISSAMENODE('/demo-features/tests')) and (p.[mgnl:activationStatus] <> '') """ def publishedAssets = damSession.query(publishedAssetsQuery).result.nodes // 2. 获取website仓库会话,收集所有已发布页面引用的资产UUID def websiteSession = MgnlContext.getJCRSession('website') def publishedPagesQuery = """ select p.* from [mgnl:page] as p where p.[mgnl:activationStatus] <> '' """ def publishedPages = websiteSession.query(publishedPagesQuery).result.nodes def referencedAssetUuids = [] publishedPages.each { pageNode -> // 遍历页面所有属性,找出引用资产的字段(根据你实际的引用方式调整) pageNode.properties.each { prop -> def propValue = prop.string if (propValue) { // 处理UUID格式的引用(比如jcr:uuid:abc123) if (propValue.startsWith('jcr:uuid:')) { referencedAssetUuids.add(propValue.substring(9)) } // 处理路径格式的引用(比如/demo-features/tests/my-asset) else if (propValue.startsWith('/dam/')) { def assetNode = damSession.getNodeIfExists(propValue) if (assetNode) { referencedAssetUuids.add(assetNode.identifier) } } } } } // 3. 筛选出已发布但未被已发布页面引用的资产 def orphanedAssets = publishedAssets.findAll { assetNode -> !referencedAssetUuids.contains(assetNode.identifier) } // 输出结果 println "找到 ${orphanedAssets.size()} 个符合条件的资产:" orphanedAssets.each { asset -> println "- 路径: ${asset.path} | UUID: ${asset.identifier}" }
方案2:利用Magnolia的ReferencesService API(更优雅)
Magnolia内置了ReferencesService,可以直接查找某个资产被哪些节点引用,然后我们只需要检查这些引用节点所在的页面是否已发布即可。
Java代码示例(适合集成到自定义模块)
import info.magnolia.jcr.util.NodeUtil; import info.magnolia.reference.ReferenceType; import info.magnolia.reference.ReferencesService; import info.magnolia.repository.RepositoryConstants; import info.magnolia.context.MgnlContext; import javax.jcr.Node; import javax.jcr.Session; import javax.jcr.query.Query; import java.util.List; public class OrphanedAssetFinder { public void findOrphanedPublishedAssets() throws Exception { // 1. 获取已发布的目标资产 Session damSession = MgnlContext.getJCRSession(RepositoryConstants.DAM); String damQuery = "select p.* from [mgnl:asset] as p where (ISDESCENDANTNODE('/demo-features/tests') or ISSAMENODE('/demo-features/tests')) and (p.[mgnl:activationStatus] <> '')"; Query query = damSession.getWorkspace().getQueryManager().createQuery(damQuery, Query.JCR_SQL2); List<Node> publishedAssets = NodeUtil.getNodes(query.execute().getNodes()); // 2. 注入ReferencesService(通过Magnolia的依赖注入) ReferencesService referencesService = MgnlContext.getInjector().getInstance(ReferencesService.class); // 3. 逐个检查资产的引用页面是否已发布 for (Node asset : publishedAssets) { // 获取所有引用该资产的节点(限定在website仓库) List<Node> references = referencesService.getReferences(asset, ReferenceType.REFERENCE, RepositoryConstants.WEBSITE); // 检查是否存在至少一个已发布的引用页面 boolean hasPublishedPageReference = references.stream() .map(refNode -> { try { // 找到引用节点所在的页面(向上遍历到mgnl:page节点) return NodeUtil.getNearestAncestor(refNode, "mgnl:page"); } catch (Exception e) { return null; } }) .filter(pageNode -> pageNode != null) .anyMatch(pageNode -> { try { return pageNode.hasProperty("mgnl:activationStatus") && !pageNode.getProperty("mgnl:activationStatus").getString().isEmpty(); } catch (Exception e) { return false; } }); // 如果没有已发布的页面引用,输出该资产 if (!hasPublishedPageReference) { System.out.println("Orphaned published asset: " + asset.getPath()); } } } }
关键注意事项
- 页面引用资产的方式可能因项目而异:有的用UUID格式(
jcr:uuid:xxx),有的用绝对路径,有的用自定义字段,你需要根据自己项目的实际情况调整查询或属性提取逻辑。 - 性能考虑:如果你的网站页面和资产数量很大,建议给
mgnl:activationStatus属性建立索引,避免全表扫描导致的性能问题。
内容的提问来源于stack exchange,提问作者Fb.SegoviA
相关产品推荐
相关产品推荐

