diff --git a/lib/model.js b/lib/model.js
index 86695ad84ca..bd548293190 100644
--- a/lib/model.js
+++ b/lib/model.js
@@ -1341,9 +1341,9 @@ Model.syncIndexes = function syncIndexes(options, callback) {
 /**
  * Deletes all indexes that aren't defined in this model's schema. Used by
  * `syncIndexes()`.
- * 
+ *
  * The returned promise resolves to a list of the dropped indexes' names as an array
- * 
+ *
  * @param {Function} [callback] optional callback
  * @return {Promise|undefined} Returns `undefined` if callback is specified, returns a promise if no callback.
  * @api public
diff --git a/lib/schema.js b/lib/schema.js
index 1aac5594522..f2f04bc70f6 100644
--- a/lib/schema.js
+++ b/lib/schema.js
@@ -6,6 +6,7 @@
 
 const EventEmitter = require('events').EventEmitter;
 const Kareem = require('kareem');
+const MongooseError = require('./error/mongooseError');
 const SchemaType = require('./schematype');
 const SchemaTypeOptions = require('./options/SchemaTypeOptions');
 const VirtualType = require('./virtualtype');
@@ -332,6 +333,49 @@ Schema.prototype.clone = function() {
   return s;
 };
 
+/**
+ * Returns a new schema that has the picked `paths` from this schema.
+ *
+ * This method is analagous to [Lodash's `pick()` function](https://lodash.com/docs/4.17.15#pick) for Mongoose schemas.
+ *
+ * ####Example:
+ *
+ *     const schema = Schema({ name: String, age: Number });
+ *     // Creates a new schema with the same `name` path as `schema`,
+ *     // but no `age` path.
+ *     const newSchema = schema.pick(['name']);
+ *
+ *     newSchema.path('name'); // SchemaString { ... }
+ *     newSchema.path('age'); // undefined
+ *
+ * @param {Array} paths list of paths to pick
+ * @param {Object} [options] options to pass to the schema constructor. Defaults to `this.options` if not set.
+ * @return {Schema}
+ * @api public
+ */
+
+Schema.prototype.pick = function(paths, options) {
+  const newSchema = new Schema({}, options || this.options);
+  if (!Array.isArray(paths)) {
+    throw new MongooseError('Schema#pick() only accepts an array argument, ' +
+      'got "' + typeof paths + '"');
+  }
+
+  for (const path of paths) {
+    if (this.nested[path]) {
+      newSchema.add({ [path]: get(this.tree, path) });
+    } else {
+      const schematype = this.path(path);
+      if (schematype == null) {
+        throw new MongooseError('Path `' + path + '` is not in the schema');
+      }
+      newSchema.add({ [path]: schematype });
+    }
+  }
+
+  return newSchema;
+};
+
 /**
  * Returns default options for this schema, merged with `options`.
  *
diff --git a/test/schema.test.js b/test/schema.test.js
index 30ca6a7c59d..b8b1d1dab51 100644
--- a/test/schema.test.js
+++ b/test/schema.test.js
@@ -1704,8 +1704,10 @@ describe('schema', function() {
     });
 
     it('removes a single path', function(done) {
+      assert.ok(this.schema.paths.a);
       this.schema.remove('a');
       assert.strictEqual(this.schema.path('a'), undefined);
+      assert.strictEqual(this.schema.paths.a, void 0);
       done();
     });
 
@@ -2168,4 +2170,79 @@ describe('schema', function() {
 
     assert.equal(newSchema.path('title').options.type, String);
   });
+
+  describe('pick() (gh-8207)', function() {
+    it('works with nested paths', function() {
+      const schema = Schema({
+        name: {
+          first: {
+            type: String,
+            required: true
+          },
+          last: {
+            type: String,
+            required: true
+          }
+        },
+        age: {
+          type: Number,
+          index: true
+        }
+      });
+      assert.ok(schema.path('name.first'));
+      assert.ok(schema.path('name.last'));
+
+      let newSchema = schema.pick(['age']);
+      assert.ok(!newSchema.path('name.first'));
+      assert.ok(newSchema.path('age'));
+      assert.ok(newSchema.path('age').index);
+
+      newSchema = schema.pick(['name']);
+      assert.ok(newSchema.path('name.first'));
+      assert.ok(newSchema.path('name.first').required);
+      assert.ok(newSchema.path('name.last'));
+      assert.ok(newSchema.path('name.last').required);
+      assert.ok(!newSchema.path('age'));
+
+      newSchema = schema.pick(['name.first']);
+      assert.ok(newSchema.path('name.first'));
+      assert.ok(newSchema.path('name.first').required);
+      assert.ok(!newSchema.path('name.last'));
+      assert.ok(!newSchema.path('age'));
+    });
+
+    it('with single nested paths', function() {
+      const schema = Schema({
+        name: Schema({
+          first: {
+            type: String,
+            required: true
+          },
+          last: {
+            type: String,
+            required: true
+          }
+        }),
+        age: {
+          type: Number,
+          index: true
+        }
+      });
+      assert.ok(schema.path('name.first'));
+      assert.ok(schema.path('name.last'));
+
+      let newSchema = schema.pick(['name']);
+      assert.ok(newSchema.path('name.first'));
+      assert.ok(newSchema.path('name.first').required);
+      assert.ok(newSchema.path('name.last'));
+      assert.ok(newSchema.path('name.last').required);
+      assert.ok(!newSchema.path('age'));
+
+      newSchema = schema.pick(['name.first']);
+      assert.ok(newSchema.path('name.first'));
+      assert.ok(newSchema.path('name.first').required);
+      assert.ok(!newSchema.path('name.last'));
+      assert.ok(!newSchema.path('age'));
+    });
+  });
 });