Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Mar 29, 2011 @ 11:36
    Jeroen Breuer
    0

    Query multiple websites

    Hello,

    I've got several websites in one Umbraco installation and now I'm going to build a portal which needs to be able to query data over all the other websites in this installation. What is the best way to do this? I need to use some specific queries so I thought Linq2Umbraco would be great for this. For example I could do this:

    Project project =
    (
    from project in UmbracoDataContext.Projects
    where project.CreatorID == id
    && project.Hide == false
    select project
    ).Single();

    Projects is a documenttype used on all the websites so this seems like the perfect solution, but I've heard Linq2Umbraco could be a bit slow with a lot of content. Maybe I could use examine for this, but can I also use complex queries like the above with examine? Could I try the Examine Provider for LINQ2Umbraco for this? Any other suggestions to fetch the data quickly?

    Jeroen

  • Sebastiaan Janssen 5045 posts 15477 karma points MVP admin hq
    Mar 29, 2011 @ 11:41
    Sebastiaan Janssen
    3

    If it's 4.7, use Razor. L2U is slow with only 2000 nodes, so not an ideal solution.

    It it is not 4.7, XSLT or the nodeFactory would be easiest (IMHO). As an addition to nodeFactory, use Hendy Racher's excellent uQuery. Even in 4.7 I would recommend uQuery in Razor. Haven't played enough with UQL but that might be a (more dynamics oriented) solution.

  • Jesper Hauge 298 posts 487 karma points c-trib
    Mar 29, 2011 @ 11:43
    Jesper Hauge
    3

    XSLT?

    <xsl:apply-templates select="$currentPage/ancestor::root//Project[./creatorId = $creatorId and ./hide != '1'][1]" />

    Regards
    Jesper Hauge

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Mar 29, 2011 @ 12:06
    Jeroen Breuer
    0

    @sebastiaan I haven't done much with razor yet, but how can I use razor to query data over all the data? uQuery and UQL seem like good alternatives!

    @Jesper That is a nice xpath! Guess there are plenty of options for me to choose from :).

    Jeroen

  • Hendy Racher 863 posts 3849 karma points MVP 2x admin c-trib
    Mar 29, 2011 @ 12:52
    Hendy Racher
    1

    Hi Jeroen,

    XPath would probably be the quickest (esp as it's compiled and cached):

    using System.Linq;
    using umbraco.presentation.nodeFactory;
    using uComponents.Core;

    int creatorId = 123;
    Node project = uQuery.GetNodesByXPath("//Project[@CreatorID=" +
    creatorId + " and @Hide != '1'][1]").FirstOrDefault();

    Or via the nodeFactory:

    using System.Linq;
    using umbraco.presentation.nodeFactory;
    using uComponents.Core;
    using uComponents.Core.uQueryExtensions;

    int creatorId = 123
    Node project = uQuery.GetRootNode()
    .GetDescendantNodes()
    .Where(node=> node.GetProperty<int>("CreatorID") ==
    creatorId && node.GetProperty<bool>("Hide") == false)
    .FirstOrDefault();

    HTH,

    Hendy

     

  • Sebastiaan Janssen 5045 posts 15477 karma points MVP admin hq
    Mar 29, 2011 @ 13:00
    Sebastiaan Janssen
    0

    @Jeroen - Yup, just use Hendy's code in a Razor template, very easy.

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Mar 29, 2011 @ 13:05
    Jeroen Breuer
    0

    These samples look awesome! Thanks for the help :).

    Jeroen

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Apr 05, 2011 @ 12:05
    Jeroen Breuer
    0

    Does anybody know if UQL is stable enough? Seems to be exactly what I need. Beside all the good samples I got here could this also be done with examine?

    Jeroen

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Apr 18, 2011 @ 15:51
    Jeroen Breuer
    0

    Here's another question about an interesting query :).

    I've got a parent documenttype (BaseVisuals) and some child documenttypes like this:

    In the tree it looks like this:

    The "Kenniskamer" node is of the documenttype "Chamer" which wasn't in the screenshot, but some of the children are documenttypes which have "BaseVisuals" as a parent. Now how can I query all the nodes which have "BaseVisuals" as a parent documenttype? In Linq2Umbraco I can do it like this:

    //Use Linq2Umbraco to get all the BaseVisuals subitems per chamber.
    //BaseVisuals is the base class/documenttype for many different classes/documenttypes used in Umbraco, because of this each subitem in the chamber has the required properties.
    //Example of some classes/documenttypes which inherit from BaseVisuals: Employee, Project, Content.
    from baseVisualNode in chamberNode.Children.OfType<BaseVisuals>()

    All the classes in Linq2Umbraco inherit from the "BaseVisuals" class so I've tested this code and it works, but Linq2Umbraco is a bit slow so can I also write this with UQL, uQuery or XPath and how?

    Jeroen

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Apr 18, 2011 @ 16:38
    Jeroen Breuer
    0

    If I can't query all the nodes with a documenttype that have the some base documenttype what would be the best alternative? Can I do an xpath which looks for multiple documenttypes/elements instead of just one (never needed an xpath for more than 1 kind of documenttype/element so no idea)?

    Jeroen

  • Jonas Eriksson 930 posts 1825 karma points
    Apr 18, 2011 @ 17:05
    Jonas Eriksson
    0

    Hi Jeroen!

    Just a small note about UQL. It is in alpha stage + it has a pretty impressive test coverage. https://bitbucket.org/ElijahGlover/umbraco.uql/wiki/Home . I would expect it to work very good. My XPath knowledge is at the trial-and-error-level, but I think it's should be possible to do what you are after in a nice compressed syntax, I guess we can expect an answer from the Chuck Norris of Xslt & Xpath :) before we know it.

    Regards

    Jonas

  • Chriztian Steinmeier 2798 posts 8788 karma points MVP 7x admin c-trib
    Apr 18, 2011 @ 18:01
    Chriztian Steinmeier
    0

    Hi Jeroen,

    Not sure if I understand this fully, but I kinda reckon you're asking if it's possible to select all of those types with an XPath (?) - which is possible with the pipe character (think of it as a join operator). If your current context node is a 'Chamber' node, use an XPath like this: 

    "Calendar | Contact | Content | Employee | NewsTweets | Project | Search | Whitepaper"

     

    It's easiest if they are direct children, but it's possible even if they're scattered all over the place...

    /Chriztian 

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Apr 18, 2011 @ 18:26
    Jeroen Breuer
    0

    Hello,

    I used that example from a different project. I'm starting on a new project in which the documenttypes (with the same base) are scatterd over different websites that are in 1 umbraco instance. So I guess I could search all the nodes with something like this:

    //doctype1 | //doctype2

    or if all the documenttypes have a unique property that's inherited from the base documenttype:

    //*[propertyName]

    This provides me with a nice (and hopefully faster) alternative for Linq2Umbraco.

    Now for the next challenge ;-). In one of the properties I store a google maps location (from the Google Maps 2.0 datatype) and in the XPath where I'm searching for the nodes I only want to return nodes in a certain range and sorted by the closest location. Can I do that in 1 XPath? So look for multiple different nodes or 1 property and do a bewteen on one of the properties with google maps lat long values? I know this is getting complicated, but I want to provide the best possible solution for this situation and I think I'm getting there :-).

    Jeroen

     

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Apr 18, 2011 @ 18:31
    Jeroen Breuer
    0

    Maybe I could also increase performance by using the key feature of xslt? Not sure if I can do such a complicated xpath on it though. Topic: http://our.umbraco.org/forum/developers/api-questions/18933-Query-multiple-websites?p=1#comment74274.

    Not sure I'm going to solve it with xslt. Could also use Razor or a usercontrol for this :).

    Jeroen

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Apr 18, 2011 @ 18:42
    Jeroen Breuer
    0

    Btw the Google maps lat long values are stored comma separated to make thing more complicated for the XPath ;-).

    Jeroen

  • RolandWolters 42 posts 63 karma points
    Apr 18, 2011 @ 20:35
    RolandWolters
    0

    If you need lightning blazing fast, nothing beats a storedprocedure. It's a bit more hassle and surely not the cms-way but... fast. If you want, i'll write you one.

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Apr 19, 2011 @ 09:27
    Jeroen Breuer
    0

    Hi Roland,

    I know using a stored procedure can be really fast, but my question was more about how I can query data that is stored in nodes (and the xml cache). All this data is also stored in the database so a stored procedure should work, but I don't think that's the way to go for this. My best 2 options are using Linq2Umbraco (but it's a bit slow) or an advanced XPath.

    About also looking for Google maps data, perhaps it's the best If I use an XPath with uQuery.GetNodesByXPath to get all the nodes which are of a specific documenttype. After that I'll use LINQ to Objects on the returned List<Node> to get all the nodes which are in a certain range and sorted by the closest location because this could be difficult with an XPath.

    And another option I came up with is to use Linq to Xml on the umbraco cache (umbraco.content.Instance.XmlContent) to get all the data I need, but I think the XPath option still would be the best. Agree?

    Jeroen

  • RolandWolters 42 posts 63 karma points
    Apr 19, 2011 @ 11:22
    RolandWolters
    0

    HI Jeroen,

    I think the complexity of this query will result in a really bad performance. A well written storedprocedure will be  - in terms of performance -  your best option. Only thing against it is that it is less portable. (for now).

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Apr 19, 2011 @ 11:33
    Jeroen Breuer
    0

    Currently I just want the best performance since the search will be performed over a 100 websites (all in 1 Umbraco environment) with all the same documenttypes (with the same base documenttype). So if you can create a stored procedure that can query all the latested published data which all have the same base documenttype than that would be fine as well :). Thanks.

    Jeroen

  • RolandWolters 42 posts 63 karma points
    Apr 19, 2011 @ 11:48
    RolandWolters
    0

    Hi Jeroen, 

    If you send me, hand me, or let me download your database, and describe EXACTLY what you need i'll write you a storedprocedure this week. You don't have to use it, have a look at it and decide what you want. Its just I love to write sql so much :)

     

    Oh ehh I wrote "this week" but because a leave for a motorbike trip this thursday, I can only do it this week if you send it to me TODAY. Otherwise it will be next week.

    If people are interested, I'll post the storedprocedure here.

  • Marco vd Wijdeven 5 posts 27 karma points
    Apr 19, 2011 @ 14:01
    Marco vd Wijdeven
    0

    If you just need the children for the base doctypes (like BaseVisuals)

    $currentPage/ancestor::root/descendant::*[local-name()='BaseVisuals']/*[@id]

    The following might be faster (or not)

    $currentPage/ancestor::root/descendant::*[parent::BaseVisuals][@id]

    If you need specific children it becomes a bit more complicated.

     

  • Marco vd Wijdeven 5 posts 27 karma points
    Apr 19, 2011 @ 14:01
    Marco vd Wijdeven
    0

    Double post: Post removed

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Apr 19, 2011 @ 14:14
    Jeroen Breuer
    0

    Hi Marco,

    That won't work because there is no BaseVisuals parent in the xml. It's the parent of the documenttype, not the actuall node. That's what makes it so complicated. As stated here I can look for all the required documenttypes (not looking at the parent) or look for a unique property that is defined on the base documenttype, which means all child documenttypes have this property.

    Jeroen

  • Marco vd Wijdeven 5 posts 27 karma points
    Apr 19, 2011 @ 14:26
    Marco vd Wijdeven
    0

    Can't you just write an extension function then that uses the nodeType attribute to retrieve the parentNode alias? And then match that?

    ../descendant::*[foo:bar(@nodeType)='BaseVisuals']

    If you use some kind of caching inside the foo:bar function to limit database calls it should be pretty fast on that side of the xpath.

    Or am I completely misunderstanding your problem?

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Apr 19, 2011 @ 14:31
    Jeroen Breuer
    0

    Hmm an extension could solve the problem, but I'm not going to use the XPath in xslt. I want to execute the XPath in C# (propaby with uQuery), but is it possible to use some sort of extension in an XPath like that?

    Jeroen

  • Marco vd Wijdeven 5 posts 27 karma points
    Apr 19, 2011 @ 14:53
    Marco vd Wijdeven
    1

    You can parse xml using XsltCompiledTransform and passing an XsltArgumentList with the appriopate extension objects.

    For details and example see http://msdn.microsoft.com/en-us/library/system.xml.xsl.xsltargumentlist.addextensionobject.aspx

    But this is again XSLT only and not direct Xpath queries. The basic problem here is that you are trying to make an xpath statement based on a parameter that doesn't exist in the xml (the nodeType of the parent). So the only way is to format your xpath beforehand using the parameters you want (in this case the nodeTypes of the children).

    If you have a list of valid nodeTypes in your C# code (which you can retrieve if you have the parent nodeType) you can enter them in an xpath statement using something like this:

    /descendant::*[contains(';1234;4321;4567;8765;',concat(';',@nodeType,';'))]
  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Apr 19, 2011 @ 15:03
    Jeroen Breuer
    0

    Hi Marco,

    That is a good solution! Too bad I can't use some sort of extension in an XPath I want to execute in C#. So this won't work?

    xPathNavigator.Select(xPathNavigator.Compile("/descendant::*[foo:bar(@nodeType)='BaseVisuals']"))

    Because the foo:bar isn't available in C# right?

    I think you sample with contains and concat can work :). Thanks!

    Jeroen

  • Jeroen Breuer 4908 posts 12265 karma points MVP 4x admin c-trib
    Jun 30, 2011 @ 12:59
    Jeroen Breuer
    1

    I marked Marco his post as the answer because that helped me out the most. I ended up using a combination of LinqToXml and XPath. Here are some code pieces:

    Get the complete Umbraco xml:

    XDocument umbracoXml = XDocument.Parse(UmbracoContext.Current.GetXml().OuterXml);

    Use LinqToXml to get an XElement we need to do some business logic on which we can't do with XPath:

    foreach (XElement location in umbracoXml.Root.Elements("TopNode").Elements("location"))

    This is the XPath that searches through the filtered LinqToXml location elements:

    string xPath = "descendant::*[@isDoc " +
                    "and contains('" + documentTypeIds + "',concat(',',@nodeType,',')) " +
                    "and contains(concat(',',phase,','),'" + phases + "') " +
                    "and contains('" + buyOrRent + "',concat(',',buyOrRent,',')) " +
                    "and ((priceFrom >= " + startPrice + " and priceFrom <= " + endPrice + ") "+
                    "or (priceTill >= " + startPrice + " and priceTill <= " + endPrice + "))]";

    The results that I get back from the XPath will be transforemed into a DynamicNodeList which will be rendered with Razor.

    Thanks everyone for helping! h5yr

    Jeroen

Please Sign in or register to post replies

Write your reply to:

Draft