Intersection

To allow users to Intersect queries on the server-side and return only documents that match all the provided sub-queries we have introduced the query intersection feature.

Lets consider a case, where we have a T-Shirt class:

public class TShirt
{
	public string Id { get; set; }

	public int ReleaseYear { get; set; }

	public string Manufacturer { get; set; }

	public List<TShirtType> Types { get; set; }
}

public class TShirtType
{
	public string Color { get; set; }

	public string Size { get; set; }
}

And we fill our database with few records:

session.Store(new TShirt
{
	Id = "tshirts/1",
	Manufacturer = "Raven",
	ReleaseYear = 2010,
	Types = new List<TShirtType>
			{
				new TShirtType {Color = "Blue", Size = "Small"},
				new TShirtType {Color = "Black", Size = "Small"},
				new TShirtType {Color = "Black", Size = "Medium"},
				new TShirtType {Color = "Gray", Size = "Large"}
			}
});

session.Store(new TShirt
{
	Id = "tshirts/2",
	Manufacturer = "Wolf",
	ReleaseYear = 2011,
	Types = new List<TShirtType>
			{
				new TShirtType { Color = "Blue",  Size = "Small" },                                    
				new TShirtType { Color = "Black", Size = "Large" },
				new TShirtType { Color = "Gray",  Size = "Medium" }
			}
});

session.Store(new TShirt
{
	Id = "tshirts/3",
	Manufacturer = "Raven",
	ReleaseYear = 2011,
	Types = new List<TShirtType>
			{
				new TShirtType { Color = "Yellow",  Size = "Small" },
				new TShirtType { Color = "Gray",  Size = "Large" }
			}
});

session.Store(new TShirt
{
	Id = "tshirts/4",
	Manufacturer = "Raven",
	ReleaseYear = 2012,
	Types = new List<TShirtType>
			{
				new TShirtType { Color = "Blue",  Size = "Small" },
				new TShirtType { Color = "Gray",  Size = "Large" }
			}
});

Now we want to return all the T-shirts that are manufactured by Raven and contain both Small Blue and Large Gray types.

To do this, we need to do the following:

  • add Raven.Client namespace to usings
  • use Intersect query extension:

IList<TShirt> results = session.Query<TShirts_ByManufacturerColorSizeAndReleaseYear.Result, TShirts_ByManufacturerColorSizeAndReleaseYear>()
	   .Where(x => x.Manufacturer == "Raven")
	   .Intersect()
	   .Where(x => x.Color == "Blue" && x.Size == "Small")
	   .Intersect()
	   .Where(x => x.Color == "Gray" && x.Size == "Large")
	   .OfType<TShirt>()
	   .ToList();
IList<TShirt> results = session
	.Advanced
	.DocumentQuery<TShirt, TShirts_ByManufacturerColorSizeAndReleaseYear>()
	.WhereEquals("Manufacturer", "Raven")
	.Intersect()
	.WhereEquals("Color", "Blue")
	.AndAlso()
	.WhereEquals("Size", "Small")
	.Intersect()
	.WhereEquals("Color", "Gray")
	.AndAlso()
	.WhereEquals("Size", "Large")
	.ToList();
QueryResult result = store
	.DatabaseCommands
	.Query(
		"TShirts/ByManufacturerColorSizeAndReleaseYear",
		new IndexQuery
		{
			Query = "Manufacturer:Raven INTERSECT Color:Blue AND Size:Small INTERSECT Color:Gray AND Size:Large"
		});
public class TShirts_ByManufacturerColorSizeAndReleaseYear : AbstractIndexCreationTask<TShirt>
{
	public class Result
	{
		public string Manufacturer { get; set; }

		public string Color { get; set; }

		public string Size { get; set; }

		public int ReleaseYear { get; set; }
	}

	public TShirts_ByManufacturerColorSizeAndReleaseYear()
	{
		Map = tshirts => from tshirt in tshirts
						 from type in tshirt.Types
						 select new
							{
								Manufacturer = tshirt.Manufacturer,
								Color = type.Color,
								Size = type.Size,
								ReleaseYear = tshirt.ReleaseYear
							};
	}
}

Above query will return tshirts/1 and tshirts/4 as a result. Document tshirts/2 will not be included, because it is not manufactured by Raven and tshirts/3 is not available in Small Blue so it does not match all the sub-queries.