【发布时间】:2020-04-08 06:04:32
【问题描述】:
我有一个 Mongoose 架构/模型,其属性为 completedSetup,即 Date 类型。
项目回购:https://github.com/rmgreenstreet/custom-forms
const mongoose = require('mongoose');
const passportLocalMongoose = require('passport-local-mongoose');
const Schema = mongoose.Schema;
const Location = require('./location');
const Response = require('./response');
const sgMail = require('@sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const crypto = require('crypto');
const forbiddenWords = ['realtor', 'realty', 'realestate', 'agent', 'broker', 'admin'];
const userSchema = new Schema({
firstname: {
type: String,
required: true
},
lastname: {
type: String,
required: true
},
username: String,
personalEmail:{
type:String,
required:true,
unique:true
},
role:{
type:String,
default:'User'
},
isCompanyAdmin: {
type:Boolean,
default: false
},
company: {
type:Schema.Types.ObjectId,
ref: 'Company'
},
location: {
type:Schema.Types.ObjectId,
ref: 'Location'
},
image: {
url: {
type:String,
default:'https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png'
},
public_id: String
},
isExpedited: {
type:Boolean,
default:false
},
isHidden: {
type:Boolean,
default:false
},
formAccessToken: {
type: String,
default: crypto.randomBytes(16).toString('hex')
},
completedSetup: Date,
responses: [
{
type:Schema.Types.ObjectId,
ref:'Response'
}
],
createAccountToken : {
type: String,
default: crypto.randomBytes(16).toString('hex')
},
resetPasswordToken : String,
resetPasswordExpires: Date,
created:{
type:Date,
default:Date.now()
}
});
userSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model('User',userSchema);
createdDate查询:
let beginDate = new Date();
beginDate.setMonth(beginDate.getMonth() - 6);
if (req.body.beginDate) {
beginDate = new Date(req.body.beginDate);
}
let endDate = new Date();
if (req.body.endDate) {
endDate = new Date(req.body.endDate);
}
const recentSetups = await User.find({completedSetup: {$gt: beginDate, $lte: endDate}});
这将返回所有Users,而不仅仅是beginDate 和endDate 之间的completedSetup。
奇怪的是,相同的查询在其他模式/模型上正确返回,但它们的日期设置不同。
在某些模型上,我有一个 created 属性,默认设置为 Date.now(),这是在创建时设置的,查询会返回这些属性。
但是 completedSetup 的种子数据使用我定义的 pickaADate 函数来选择前一年某个时间的日期,或者从当年到当月的日期(这是一个投资组合项目仍在发展):
const fs = require('fs');
const faker = require('faker');
const crypto = require('crypto');
const Company = require('./models/company');
const Location = require('./models/location');
const User = require('./models/user');
const Form = require('./models/form');
const Question = require('./models/question');
const Response = require('./models/response');
const sampleImages = fs.readdirSync('./public/images/seeds');
function flipACoin() {
const yesOrNo = Math.floor(Math.random() *2);
// console.log(yesOrNo);
return yesOrNo;
}
async function pickADate() {
return new Promise((resolve, reject) => {
try {
const today = new Date();
const day = Math.ceil(Math.random() * 27);
// const thisOrLastYear = flipACoin();
const month = Math.ceil(Math.random() * today.getMonth())
const returnDate = new Date(today.getFullYear() - flipACoin(),month,day);
resolve(returnDate);
return;
} catch (err) {
console.log(`Error creating random date: ${err.message}`);
reject(Date.now());
return;
}
});
};
async function seedDefaultQuestions() {
try {
console.log('clearing all default questions from database')
await Question.deleteMany({});
} catch (err) {
console.log(err.message);
}
try {
console.log('adding default questions to database')
const defaultQuestionsJSON = await JSON.parse(await fs.readFileSync('./private/defaultQuestions.json'));
for (let question of defaultQuestionsJSON) {
// console.log(question);
await Question.create(question);
}
console.log(`${defaultQuestionsJSON.length} default questions added to database`);
} catch (err) {
console.log(err.message);
}
};
async function clearDatabase() {
console.log('Clearing database \n Clearing Companies');
await Company.deleteMany({});
console.log('All Companies deleted \n Clearing Locations');
await Location.deleteMany({});
console.log('All Locations deleted \n Clearing Users');
await User.deleteMany({role: {$ne:'owner'}});
console.log('All Users deleted \n Clearing Forms');
await Form.deleteMany({});
console.log('All forms deleted \n Clearing responses');
await Response.deleteMany({});
console.log('Database cleared');
};
async function seedDatabase() {
// const companyCount = Math.ceil(Math.random() * 200);
const companyCount = 10;
const defaultQuestions = await Question.find({isDefault:true});
async function createLocations(companyId) {
const locationCount = Math.ceil(Math.random() * 5);
let locationsArr = [];
for (let i = 0; i < locationCount; i++) {
let isPrimary = false;
if (i=== 0) {
isPrimary = true;
}
const randomImageIndex = Math.ceil(Math.random() * sampleImages.length);
const newLocation = await Location.create({
primary: isPrimary,
officeNumber: Math.ceil(Math.random() * 1000).toString(),
name: faker.company.companyName(),
phone: faker.phone.phoneNumber(),
fax: faker.phone.phoneNumber(),
address: {
streetNumber: Math.random(Math.ceil() * 1000),
streetName: faker.address.streetName(),
secondary: `Ste ${faker.random.alphaNumeric()}`,
city: faker.address.city(),
state: faker.address.stateAbbr(),
postal: faker.address.zipCode(),
country: 'USA'
},
website: faker.internet.url(),
images: [
{
secure_url:`/images/seeds/${sampleImages[randomImageIndex]}`
}
],
company: companyId,
created: await pickADate()
});
await newLocation.save();
newLocation.contacts = await createUsers(newLocation._id, companyId, 'Admin', (Math.ceil(Math.random() * 5)));
await newLocation.save();
console.log(`Location ${newLocation.name} created with ${newLocation.contacts.length} contacts`)
await createUsers(newLocation._id, companyId, 'User', (Math.ceil(Math.random() * 30)));
locationsArr.push(newLocation._id);
await newLocation.addDefaultForm();
}
return locationsArr;
};
async function createUsers(locationId, companyId, role, count) {
let contactsArr = [];
for (let i = 0; i < count; i++) {
const newFirstName = await faker.name.firstName();
const newLastName = await faker.name.lastName();
let newUser;
try {
newUser = await User.register({
firstname: newFirstName,
lastname: newLastName,
username: newFirstName+newLastName,
personalEmail: newFirstName+newLastName+'@test.com',
role: role,
company: companyId,
location: locationId,
formAccessToken: crypto.randomBytes(16).toString('hex'),
createAccountToken: crypto.randomBytes(16).toString('hex'),
created: await pickADate()
},'password');
} catch (err) {
if (err.message.includes('UserExistsError')) {
continue;
}
}
if(role === 'User');{
if(flipACoin()) {
newUser.responses.push(await createResponse(newUser));
await newUser.save();
} else {
continue;
}
if(flipACoin()) {
newUser.completedSetup = await pickADate();
await newUser.save();
} else {
continue;
}
};
contactsArr.push(newUser._id);
console.log(`${role} ${newUser.firstname} ${newUser.lastname} created`);
};
return contactsArr;
};
async function createResponse(user) {
return new Promise(async (resolve, reject) => {
console.log(`Creating a response for ${user.firstname}`)
const makeString = (charLimit) => {
let str = faker.lorem.paragraph()
if (str.length > charLimit) {
str = str.slice(0, charLimit - 1)
}
return str
}
let response = await Response.create({owner:user._id, created:await pickADate()});
try {
for (let question of defaultQuestions) {
const answer = {
questionId: question._id
}
if(question.inputType == 'Checkbox') {
answer.value = true;
}
if(question.inputType == 'Email') {
answer.value = faker.internet.email();
}
if(question.inputType == 'File') {
continue;
}
if(question.inputType == 'Image') {
continue;
}
if(question.inputType == 'Number') {
answer.value = Math.ceil(Math.random() * 99);
}
if(question.inputType == 'Password') {
answer.value = 'Pa55w0rd123';
}
if(question.inputType == 'Radio') {
question.value = 'No';
}
if(question.inputType == 'Select') {
question.value = "At&t";
}
if(question.inputType == 'Tel') {
answer.value = faker.phone.phoneNumber();
}
if (question.inputType == 'Text') {
if(question.maxLength) {
answer.value = makeString(question.maxLength);
} else {
answer.value = faker.lorem.words()
}
}
if(question.inputType == 'Textarea') {
answer.value = faker.lorem.paragraph();
}
if(question.inputType == 'Url') {
answer.value = faker.internet.url();
}
response.answers.push(answer);
}
await response.save();
resolve(response._id);
return;
} catch (err) {
console.log(`Error creating random response: ${err.message}.`);
reject(response);
return;
}
});
}
console.log(`Creating ${companyCount} companies`)
for(let i = 0; i < companyCount; i++) {
const newCompany = await Company.create({
name: faker.company.companyName(),
created: await pickADate()
});
newCompany.locations = await createLocations(newCompany._id);
await newCompany.save();
console.log(`${newCompany.name} created with ${newCompany.locations.length} locations`)
}
console.log('database seeded')
};
module.exports = {seedDatabase, clearDatabase, seedDefaultQuestions};
我认为问题在于该函数生成从去年年初到当前日期的随机日期,但老实说,我看不出new Date(yyyy(integer),monthIndex,day) 会有什么不同从 Date.now() 创建的日期开始,根据 MDN:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date under "Individual Date and Time Component Values"
这是用户数据在 MongoDB 中的样子,completedSetup 属性是最后一个,并且看起来格式正确:
最后,这里是一些查询返回的日志(全部达到字符限制):
[
{
image: {
url: 'https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png'
},
role: 'Admin',
isCompanyAdmin: false,
isExpedited: false,
isHidden: false,
formAccessToken: 'de5459c2cbf3ca1cbdb0a5daceb6ab61',
responses: [ 5e8b71b7e75a0726242637b9 ],
createAccountToken: 'a826054b8055243c52247a656eed9340',
created: 2020-03-04T06:00:00.000Z,
_id: 5e8b71b6e75a0726242637b8,
firstname: 'Larue',
lastname: 'Armstrong',
username: 'LarueArmstrong',
personalEmail: 'LarueArmstrong@test.com',
company: 5e8b71abe75a072624263688,
location: 5e8b71b6e75a0726242637b5,
__v: 1,
completedSetup: 2020-03-07T06:00:00.000Z
},
{
image: {
url: 'https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png'
},
role: 'User',
isCompanyAdmin: false,
isExpedited: false,
isHidden: false,
formAccessToken: '7bf9d040c0009691191f3122c14d3d51',
responses: [ 5e8b71c2e75a07262426392a ],
createAccountToken: 'b284c3f43fad0081f967f06926ee1d6d',
created: 2019-11-25T06:00:00.000Z,
_id: 5e8b71c1e75a072624263929,
firstname: 'Lance',
lastname: 'Wolff',
username: 'LanceWolff',
personalEmail: 'LanceWolff@test.com',
company: 5e8b71bfe75a0726242638dd,
location: 5e8b71bfe75a0726242638de,
__v: 1,
completedSetup: 2020-03-02T06:00:00.000Z
},
{
image: {
url: 'https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png'
},
role: 'User',
isCompanyAdmin: false,
isExpedited: false,
isHidden: false,
formAccessToken: '319cd6d626a48617c012be6c25fe66a8',
responses: [ 5e8b71c5e75a072624263977 ],
createAccountToken: '43e9161a30f7ebd672315c761da9e3d7',
created: 2019-06-03T05:00:00.000Z,
_id: 5e8b71c5e75a072624263976,
firstname: 'Kailey',
lastname: 'Ruecker',
username: 'KaileyRuecker',
personalEmail: 'KaileyRuecker@test.com',
company: 5e8b71bfe75a0726242638dd,
location: 5e8b71bfe75a0726242638de,
__v: 1,
completedSetup: 2020-02-23T06:00:00.000Z
},
{
image: {
url: 'https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png'
},
role: 'User',
isCompanyAdmin: false,
isExpedited: false,
isHidden: false,
formAccessToken: 'ccb5fc2c6ff671a8cb5bdcf432cbcb1b',
responses: [ 5e8b71c7e75a0726242639bd ],
createAccountToken: '8d3aa2ecd6e0da797d8cbf9846c78c9b',
created: 2019-04-20T05:00:00.000Z,
_id: 5e8b71c6e75a0726242639bc,
firstname: 'Skyla',
lastname: 'Dicki',
username: 'SkylaDicki',
personalEmail: 'SkylaDicki@test.com',
company: 5e8b71bfe75a0726242638dd,
location: 5e8b71bfe75a0726242638de,
__v: 1,
completedSetup: 2019-10-22T05:00:00.000Z
},
{
image: {
url: 'https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png'
},
role: 'User',
isCompanyAdmin: false,
isExpedited: false,
isHidden: false,
formAccessToken: '0641d2cf09459724ffea35d5cc96e2f1',
responses: [ 5e8b71c7e75a0726242639e0 ],
createAccountToken: '0f5e1bfd23df18835378c314efbcb206',
created: 2019-12-02T06:00:00.000Z,
_id: 5e8b71c7e75a0726242639df,
firstname: 'Rasheed',
lastname: 'Walsh',
username: 'RasheedWalsh',
personalEmail: 'RasheedWalsh@test.com',
company: 5e8b71bfe75a0726242638dd,
location: 5e8b71bfe75a0726242638de,
__v: 1,
completedSetup: 2020-02-16T06:00:00.000Z
},
{
image: {
url: 'https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png'
},
role: 'User',
isCompanyAdmin: false,
isExpedited: false,
isHidden: false,
formAccessToken: '7f584ded07bfe5b20e95ef72ed2a7749',
responses: [ 5e8b71cae75a072624263a2b ],
createAccountToken: '0934cd5e7ccb75d476ecc23624e491f1',
created: 2020-02-27T06:00:00.000Z,
_id: 5e8b71cae75a072624263a2a,
firstname: 'Leanna',
lastname: 'Kuphal',
username: 'LeannaKuphal',
personalEmail: 'LeannaKuphal@test.com',
company: 5e8b71bfe75a0726242638dd,
location: 5e8b71bfe75a0726242638de,
__v: 1,
completedSetup: 2019-11-02T05:00:00.000Z
}
]
在完整列表(大约 60 多个结果)中,有几个是在 2019 年 11 月之前,比如这个 sn-p 中的那个是从 2019 年 10 月开始的。
【问题讨论】:
-
您是否能够调查
users集合中的数据以查看您在completedSetup字段中实际拥有的日期?你能在你使用pickaADate播种completedSetup的地方显示代码吗? -
另外,
pickADate的代码无效。在捕获之前有一个}太多了。当您输入/粘贴它时是否遗漏了什么?如果是这样,请在问题中更正。 -
@abondoa 更新 :) 将 'pickADate' 替换为完整的种子功能,添加 mongoDB 屏幕截图和查询返回日志
-
还添加了项目仓库的链接:github.com/rmgreenstreet/custom-forms
-
谢谢 :) 您能否分享用于在“最后,这里是一些内容的日志...”中获取结果的查询值(
beginDate和endDate) ?查看那里的结果,似乎所有条目都有completedSetup在您查询的默认范围内(过去 6 个月内)。
标签: javascript node.js mongoose