From 5df08bee49d7edc37b498342c3d1eb8f157be56d Mon Sep 17 00:00:00 2001 From: Valerio Mazzeo Date: Mon, 18 Mar 2019 18:34:38 +0000 Subject: [PATCH 1/3] progress --- Sources/FluentMongo/Document+Nested.swift | 35 +++++++++++++++++++ Sources/FluentMongo/FluentMongoQuery.swift | 22 +++++------- .../FluentMongo/FluentMongoQueryFilter.swift | 7 ++-- .../FluentMongo/FluentMongoQueryJoin.swift | 2 +- .../FluentMongo/FluentMongoQuerySort.swift | 2 +- 5 files changed, 51 insertions(+), 17 deletions(-) diff --git a/Sources/FluentMongo/Document+Nested.swift b/Sources/FluentMongo/Document+Nested.swift index f6345af..e054b39 100644 --- a/Sources/FluentMongo/Document+Nested.swift +++ b/Sources/FluentMongo/Document+Nested.swift @@ -57,3 +57,38 @@ public extension Document { } } } + +extension Document { + + func byRemovingKeysPrefix(_ prefix: String) -> Document { + + func removeKeysPrefix(_ document: Document) -> Document { + + func ensureNoRootNameSpace(_ value: String) -> String { + let components = value.components(separatedBy: ".") + if components.first == prefix { + return components.dropFirst().joined(separator: ".") + } else { + return value + } + } + + var mutableFilter = Document() + + for item in document { + switch document[item.key] { + case .some(let value as Document): + mutableFilter[ensureNoRootNameSpace(item.key)] = removeKeysPrefix(value) + case .some(let value): + mutableFilter[ensureNoRootNameSpace(item.key)] = value + case .none: + break + } + } + + return mutableFilter + } + + return removeKeysPrefix(self) + } +} diff --git a/Sources/FluentMongo/FluentMongoQuery.swift b/Sources/FluentMongo/FluentMongoQuery.swift index 49d79d2..9bdb9f6 100644 --- a/Sources/FluentMongo/FluentMongoQuery.swift +++ b/Sources/FluentMongo/FluentMongoQuery.swift @@ -67,14 +67,14 @@ public struct FluentMongoQuery { continue } - projection[field.pathWithNamespace.joined(separator: ".")] = true + projection[(field.entity == self.collection ? field.path : field.pathWithNamespace).joined(separator: ".")] = true } guard !projection.isEmpty else { return nil } - projection[self.collection + "._id"] = true + projection["_id"] = true return projection } @@ -88,18 +88,19 @@ public struct FluentMongoQuery { continue } // It is not possible to use dots when specifying an id field for $group - id[field.pathWithNamespace.joined(separator: ":")] = "$" + field.pathWithNamespace.joined(separator: ".") + let path = (field.entity == self.collection ? field.path : field.pathWithNamespace) + id[field.pathWithNamespace.joined(separator: ":")] = "$" + path.joined(separator: ".") } if id.isEmpty { - id[self.collection + ":_id"] = "$" + self.collection + "._id" + id[self.collection + ":_id"] = "$_id" } group["_id"] = id - group["doc"] = ["$first": "$" + self.collection] as Document + group["doc"] = ["$first": "$$ROOT"] as Document stages.append(["$group": group]) - stages.append(["$project": [self.collection: "$doc"] as Document]) + stages.append(["$replaceRoot": ["newRoot": "$doc"] as Document]) return stages } @@ -122,7 +123,8 @@ public struct FluentMongoQuery { continue } // It seems that fluent only support one aggregated field - group[FluentMongoQuery.defaultAggregateField] = [accumulator.value: "$" + field.pathWithNamespace.joined(separator: ".")] as Document + let path = (field.entity == self.collection ? field.path : field.pathWithNamespace).joined(separator: ".") + group[FluentMongoQuery.defaultAggregateField] = [accumulator.value: "$" + path] as Document break } @@ -136,9 +138,6 @@ public struct FluentMongoQuery { func aggregationPipeline() -> [Document] { var pipeline = [Document]() - // Namespace root document - pipeline.append(["$project": [self.collection: "$$ROOT"] as Document]) - // Joins if !self.joins.isEmpty { pipeline.append(contentsOf: self.joins) @@ -177,9 +176,6 @@ public struct FluentMongoQuery { // Aggregates if let aggregates = self.aggregates() { pipeline.append(contentsOf: aggregates) - } else { - // Remove namespace - pipeline.append(["$replaceRoot": ["newRoot": "$" + self.collection] as Document]) } return pipeline diff --git a/Sources/FluentMongo/FluentMongoQueryFilter.swift b/Sources/FluentMongo/FluentMongoQueryFilter.swift index 67cd470..9dbe61f 100644 --- a/Sources/FluentMongo/FluentMongoQueryFilter.swift +++ b/Sources/FluentMongo/FluentMongoQueryFilter.swift @@ -50,11 +50,14 @@ extension Database where Self: QuerySupporting, Self.Query == FluentMongoQuery, } public static func queryFilterApply(_ filter: QueryFilter, to query: inout Query) { + + let filterByRemovingRootNamespace = filter.byRemovingKeysPrefix(query.collection) + switch query.filter { case .some(let document): - query.filter = [query.defaultFilterRelation.rawValue: [document, filter]] + query.filter = [query.defaultFilterRelation.rawValue: [document, filterByRemovingRootNamespace]] case .none: - query.filter = filter + query.filter = filterByRemovingRootNamespace } } } diff --git a/Sources/FluentMongo/FluentMongoQueryJoin.swift b/Sources/FluentMongo/FluentMongoQueryJoin.swift index 10bfde1..1ae8f78 100644 --- a/Sources/FluentMongo/FluentMongoQueryJoin.swift +++ b/Sources/FluentMongo/FluentMongoQueryJoin.swift @@ -34,7 +34,7 @@ extension Database where Self: JoinSupporting, Self.QueryJoin == FluentMongoQuer let lookup: Document = [ "$lookup": [ "from": collection, - "localField": base.pathWithNamespace.joined(separator: "."), + "localField": base.path.joined(separator: "."), "foreignField": joined.path.joined(separator: "."), "as": collection ] as Document diff --git a/Sources/FluentMongo/FluentMongoQuerySort.swift b/Sources/FluentMongo/FluentMongoQuerySort.swift index c1982e4..e1bab04 100644 --- a/Sources/FluentMongo/FluentMongoQuerySort.swift +++ b/Sources/FluentMongo/FluentMongoQuerySort.swift @@ -36,7 +36,7 @@ extension Database where Self: QuerySupporting, Self.Query == FluentMongoQuery, for field in sort { document[field.key] = field.value } - query.sort = document + query.sort = document.byRemovingKeysPrefix(query.collection) } } From c9a3ac723d271fe491ae0dc7cc850211ddd49ebe Mon Sep 17 00:00:00 2001 From: Valerio Mazzeo Date: Mon, 18 Mar 2019 20:28:20 +0000 Subject: [PATCH 2/3] remove joined collection from output --- Sources/FluentMongo/FluentMongoQuery.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Sources/FluentMongo/FluentMongoQuery.swift b/Sources/FluentMongo/FluentMongoQuery.swift index 9bdb9f6..a4a1ed6 100644 --- a/Sources/FluentMongo/FluentMongoQuery.swift +++ b/Sources/FluentMongo/FluentMongoQuery.swift @@ -178,6 +178,18 @@ public struct FluentMongoQuery { pipeline.append(contentsOf: aggregates) } + // Remove joined collections from the output + if !self.joins.isEmpty { + var projection = Document() + for join in self.joins { + guard let field = join["$lookup", "as"] as? String else { + continue + } + projection[field] = false + } + pipeline.append(["$project": projection]) + } + return pipeline } } From 52fae31195297d696159e560e5673489999b5969 Mon Sep 17 00:00:00 2001 From: Valerio Mazzeo Date: Tue, 19 Mar 2019 11:20:25 +0000 Subject: [PATCH 3/3] added array handling --- Sources/FluentMongo/Document+Nested.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/FluentMongo/Document+Nested.swift b/Sources/FluentMongo/Document+Nested.swift index e054b39..42e1967 100644 --- a/Sources/FluentMongo/Document+Nested.swift +++ b/Sources/FluentMongo/Document+Nested.swift @@ -79,10 +79,12 @@ extension Document { switch document[item.key] { case .some(let value as Document): mutableFilter[ensureNoRootNameSpace(item.key)] = removeKeysPrefix(value) + case .some(let value as [Document]): + mutableFilter[ensureNoRootNameSpace(item.key)] = value.map { removeKeysPrefix($0) } case .some(let value): mutableFilter[ensureNoRootNameSpace(item.key)] = value case .none: - break + mutableFilter[ensureNoRootNameSpace(item.key)] = nil } }