private void TranslateGroupJoin(GroupJoinExpression node) { Translate(node.Source); var joined = node.Joined as CollectionExpression; if (joined == null) { throw new NotSupportedException("Only a collection is allowed to be joined."); } var localFieldValue = AggregateLanguageTranslator.Translate(node.SourceKeySelector); if (localFieldValue.BsonType != BsonType.String) { throw new NotSupportedException("Could not translate the local field."); } var localField = localFieldValue.ToString().Substring(1); // remove '$' var foreignFieldValue = AggregateLanguageTranslator.Translate(node.SourceKeySelector); if (foreignFieldValue.BsonType != BsonType.String) { throw new NotSupportedException("Could not translate the foreign field."); } var foreignField = foreignFieldValue.ToString().Substring(1); // remove '$' _stages.Add(new BsonDocument("$lookup", new BsonDocument { { "from", ((CollectionExpression)node.Joined).CollectionNamespace.CollectionName }, { "localField", localField }, { "foreignField", foreignField }, { "as", node.JoinedItemName } })); }
public Expression Bind(PipelineExpression pipeline, PipelineBindingContext bindingContext, MethodCallExpression node, IEnumerable <Expression> arguments) { var args = arguments.ToList(); var joined = bindingContext.Bind(args[0]) as CollectionExpression; if (joined == null) { throw new NotSupportedException("The joined collection cannot have any qualifiers."); } var sourceKeySelectorLambda = ExpressionHelper.GetLambda(args[1]); bindingContext.AddExpressionMapping(sourceKeySelectorLambda.Parameters[0], pipeline.Projector); var sourceKeySelector = bindingContext.Bind(sourceKeySelectorLambda.Body) as IFieldExpression; if (sourceKeySelector == null) { var message = string.Format("Unable to determine the serialization information for the outer key selector in the tree: {0}", node.ToString()); throw new NotSupportedException(message); } var joinedArraySerializer = joined.Serializer as IBsonArraySerializer; BsonSerializationInfo joinedItemSerializationInfo; if (joinedArraySerializer == null || !joinedArraySerializer.TryGetItemSerializationInfo(out joinedItemSerializationInfo)) { var message = string.Format("Unable to determine the serialization information for the inner collection: {0}", node.ToString()); throw new NotSupportedException(message); } var joinedKeySelectorLambda = ExpressionHelper.GetLambda(args[2]); var joinedDocument = new DocumentExpression(joinedItemSerializationInfo.Serializer); bindingContext.AddExpressionMapping(joinedKeySelectorLambda.Parameters[0], joinedDocument); var joinedKeySelector = bindingContext.Bind(joinedKeySelectorLambda.Body) as IFieldExpression; if (joinedKeySelector == null) { var message = string.Format("Unable to determine the serialization information for the inner key selector in the tree: {0}", node.ToString()); throw new NotSupportedException(message); } var resultSelectorLambda = ExpressionHelper.GetLambda(args[3]); var sourceSerializer = pipeline.Projector.Serializer; var joinedSerializer = node.Method.Name == "GroupJoin" ? joined.Serializer : joinedItemSerializationInfo.Serializer; var sourceDocument = new DocumentExpression(sourceSerializer); var joinedField = new FieldExpression( resultSelectorLambda.Parameters[1].Name, joinedSerializer); bindingContext.AddExpressionMapping( resultSelectorLambda.Parameters[0], sourceDocument); bindingContext.AddExpressionMapping( resultSelectorLambda.Parameters[1], joinedField); var resultSelector = bindingContext.Bind(resultSelectorLambda.Body); Expression source; if (node.Method.Name == "GroupJoin") { source = new GroupJoinExpression( node.Type, pipeline.Source, joined, (Expression)sourceKeySelector, (Expression)joinedKeySelector, resultSelectorLambda.Parameters[1].Name); } else { source = new JoinExpression( node.Type, pipeline.Source, joined, (Expression)sourceKeySelector, (Expression)joinedKeySelector, resultSelectorLambda.Parameters[1].Name); } SerializationExpression projector; var newResultSelector = resultSelector as NewExpression; if (newResultSelector != null && newResultSelector.Arguments[0] == sourceDocument && newResultSelector.Arguments[1] == joinedField) { Func <object, object, object> creator = (s, j) => Activator.CreateInstance(resultSelector.Type, s, j); var serializer = (IBsonSerializer)Activator.CreateInstance( typeof(JoinSerializer <>).MakeGenericType(resultSelector.Type), sourceSerializer, newResultSelector.Members[0].Name, joinedSerializer, newResultSelector.Members[1].Name, resultSelectorLambda.Parameters[1].Name, creator); projector = new DocumentExpression(serializer); } else { projector = bindingContext.BindProjector(ref resultSelector); source = new SelectExpression( source, "__i", // since this is a top-level pipeline, this doesn't matter resultSelector); } return(new PipelineExpression( source, projector)); }