Mongoose: ๊ธฐ๋ณธ ๋ชจ๋ธ์€ ์„ ํƒ์„ ์กด์ค‘ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค: ํŒ๋ณ„์ž์˜ ๊ฒฝ์šฐ false

์— ๋งŒ๋“  2017๋…„ 02์›” 16์ผ  ยท  3์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: Automattic/mongoose

๊ธฐ๋Šฅ ์„ ์š”์ฒญํ•˜๊ฑฐ๋‚˜ ๋ฒ„๊ทธ๋ฅผ ๋ณด๊ณ  ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?
๋ฒŒ๋ ˆ

ํ˜„์žฌ ํ–‰๋™์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?
๊ธฐ๋ณธ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ํŒ๋ณ„์ž ๋ชจ๋ธ ๋ฌธ์„œ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š” ๊ฒฝ์šฐ select: false ์ธ์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ๋™์ž‘์ด ๋ฒ„๊ทธ์ธ ๊ฒฝ์šฐ ์žฌํ˜„ ๋‹จ๊ณ„๋ฅผ ์ œ๊ณตํ•˜์‹ญ์‹œ์˜ค.

const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
const co = require('co');
const chalk = require('chalk');

const GITHUB_ISSUE = `test-constructor-emit-bug`;

exec()
  .then(() => {
    console.log(chalk.green(`Successfully ran program`));
    process.exit(0);
  })
  .catch(error => {
    console.log(chalk.red(`Error: ${ error }\n${ error.stack }`));
    process.exit(2);
  });

function exec() {
  return co(function* () {
    const db = mongoose.createConnection(`mongodb://localhost:27017/${ GITHUB_ISSUE }`);
    const { Base, Discriminator } = createModels(db);
    const { baseDoc, discrimDoc } = yield seedDb({ Base, Discriminator });

    const docFromDb = yield Base.findById(discrimDoc._id) // does not honor select: false
    // const docFromDb = yield Discriminator.findById(discrimDoc._id); // honors select: false
    console.log(docFromDb.internal); // should not log `internal.password`
  });
}

function seedDb(models) {
  return co(function*() {
    const { Base, Discriminator } = models;

    yield [Base.remove({}), Discriminator.remove({})];

    const baseDoc = yield Base.create({ internal: { diseases: ['Malaria'] }});
    const discrimDoc = yield Discriminator.create({ internal: {
      diseases: ['MS'],
      password: 'plain_test_password_ftw'
    }});

    return { baseDoc, discrimDoc };
  });
}

function createModels(db) {
  const baseSchema = new mongoose.Schema({
    internal: {
      diseases: [{ type: String }]
    }
  });

  const Base = db.model('Base', baseSchema);
  const discriminatorSchema = new mongoose.Schema({
    internal: {
      password: { type: String, select: false }
    }
  });
  const Discriminator = Base.discriminator('Discriminator', discriminatorSchema);

  return { Base, Discriminator };
}

์˜ˆ์ƒ๋˜๋Š” ๋™์ž‘์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?
mongoose๋Š” ์–ด๋–ค ํŒ๋ณ„์ž๋ฅผ ์„ ํƒํ• ์ง€ ๋ฏธ๋ฆฌ ์•Œ์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๊ฐ€์ ธ์˜จ ํ›„ ํ•ด๋‹น ํ•„๋“œ๋ฅผ ์ˆ˜๋™์œผ๋กœ ์„ ํƒ ์ทจ์†Œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

node.js, mongoose ๋ฐ MongoDB ๋ฒ„์ „์„ ์–ธ๊ธ‰ํ•˜์‹ญ์‹œ์˜ค.
๋…ธ๋“œ 6.9.2, ๋ชฝ๊ตฌ์Šค 4.8.3, mongodb 3.4

confirmed-bug

๋ชจ๋“  3 ๋Œ“๊ธ€

์ด ๋ณ€๊ฒฝ์œผ๋กœ ์ธํ•ด ์˜ˆ๊ธฐ์น˜ ์•Š์€ ๋ถ€์ž‘์šฉ์ด ๋ฐœ์ƒํ•œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

ํŒ๋ณ„์ž ๋ชจ๋ธ B ๊ฐ€ ์žˆ๋Š” ๊ธฐ๋ณธ ๋ชจ๋ธ A B ์žˆ์Šต๋‹ˆ๋‹ค.
$slice ๋ฐฐ์—ด ํ”„๋กœ์ ์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์„œ์— ๋Œ€ํ•ด A๋ฅผ ์ฟผ๋ฆฌํ•  ๋•Œ A ์œ ํ˜•์˜ ๊ฒฐ๊ณผ ๋ฌธ์„œ๋Š” ๋ชจ๋“  ์†์„ฑ( select: false ๋กœ ํ‘œ์‹œ๋œ ๋ฌธ์„œ ์ œ์™ธ)์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐ˜๋ฉด B ์œ ํ˜•์˜ ๊ฒฐ๊ณผ ๋ฌธ์„œ๋Š” select: true ๋กœ ํ‘œ์‹œ๋œ ์†์„ฑ ๋˜๋Š” default ์„ค์ •๋œ ์†์„ฑ๋งŒ _๋ช…์‹œ์ ์œผ๋กœ_ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. default ์„ค์ •๋œ ๊ฐ’์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์‹ค์ œ๋กœ ์ €์žฅ๋œ ๊ฐ’์ด ์•„๋‹ˆ๋ผ ๊ธฐ๋ณธ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. select: true ๋กœ ํ‘œ์‹œ๋œ ์†์„ฑ์ด ์—†์œผ๋ฉด default ๊ฐ’์ด ์žˆ๋Š” ์†์„ฑ๋งŒ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค(์ €์žฅ ๊ฐ’์ด ์•„๋‹Œ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๋‹ค์‹œ ํ‘œ์‹œ๋จ).

ํŽธ์ง‘ : ๋‚ด ์˜๊ฒฌ์„ ๋ฌด์‹œํ•˜์‹ญ์‹œ์˜ค. ๋ฌธ์ œ๋Š” ๋ชฝ๊ตฌ์Šค๊ฐ€ ํ›„๋“œ ์•„๋ž˜์˜ ์ฟผ๋ฆฌ์— ํŒ๋ณ„์ž ํ‚ค๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•ด๊ฒฐ์ฑ…์€ ์ฟผ๋ฆฌ์—์„œ slice ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋„ˆ๋ฌด ๋นจ๋ฆฌ ๋งํ–ˆ์„ ์ˆ˜๋„ ์žˆ๋‹ค. ๋ฒ„์ „ 4.13.4์™€ ์ตœ์‹  master ์ปค๋ฐ‹์œผ๋กœ ํ…Œ์ŠคํŠธํ•œ ๊ฒฐ๊ณผ slice ํ”„๋กœ์ ์…˜๋งŒ ์‚ฌ์šฉํ•  ๋•Œ ๋™์ผํ•œ ๋™์ž‘์ด ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ์˜ ์›๋ž˜ ์˜ˆ๋ฅผ ์ทจํ•˜๊ณ  ๋™์ž‘์„ ์žฌํ˜„ํ•˜๋„๋ก ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
const co = require('co');
const chalk = require('chalk');
mongoose.set('debug', true);
const GITHUB_ISSUE = `default-values-on-discriminator-documents`;

exec()
    .then(() => {
        console.log(chalk.green(`Successfully ran program`));
        process.exit(0);
    })
    .catch(error => {
        console.log(chalk.red(`Error: ${error}\n${error.stack}`));
        process.exit(2);
    });

function exec() {
    return co(function* () {
        const db = mongoose.createConnection(`mongodb://localhost:27017/${GITHUB_ISSUE}`);
        const { Base, Discriminator } = createModels(db);
        const { baseDoc, discrimDoc } = yield seedDb({ Base, Discriminator });

        const baseDocsFromDbWithSlice = yield Base.find().slice('array', 1)
        const baseDocsFromDb = yield Base.find()
        console.log(baseDocsFromDbWithSlice); // Discriminator document returns default value for propA (and not propB), base document returns stored value - unexpected
        console.log(baseDocsFromDb); // Discriminator and base document returns stored value for propA - expected
    });
}

function seedDb(models) {
    return co(function* () {
        const { Base, Discriminator } = models;

        yield [Base.remove({}), Discriminator.remove({})];

        const baseDoc = yield Base.create({
            propA: 'Hi',
            array: ["a", "b"]
        });
        const discrimDoc = yield Discriminator.create({
            propA: 'Hi',
            propB: 'Hello',
            array: ["a", "b"]
        });

        return { baseDoc, discrimDoc };
    });
}

function createModels(db) {
    const baseSchema = new mongoose.Schema({
        propA: { type: String, default: 'default value' },
        array: [{type: String}],
    });

    const Base = db.model('Base', baseSchema);
    const discriminatorSchema = new mongoose.Schema({
        propB: { type: String}
    });
    const Discriminator = Base.discriminator('Discriminator', discriminatorSchema);

    return { Base, Discriminator };
}

์ด ๋™์ž‘์€ 4.11.13 ์—์„œ ๋ณ€๊ฒฝ๋˜์—ˆ์œผ๋ฏ€๋กœ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์˜์‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ ๊ธฐ๊บผ์ด ์ƒˆ ๋ฌธ์ œ๋ฅผ ๋งŒ๋“ค๊ฒ ์Šต๋‹ˆ๋‹ค.

@bruun ์„ ์‹ ๊ณ 

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰