小黄车真要黄了!
截止目前,已有超过1000万人提交ofo的线上退款申请,还有几千人直接等在ofo总部等待线下退款。
如果按照押金99元来算,戴威需要还9.9亿,如果押金是199元的话,需要还19.9亿元。但如何筹备资金退还这些钱,戴威没公布具体方案。
日前,戴威在全员信中说:“我希望每一位ofo人都能认同并坚定信念:不逃避,勇敢活下去,为我们欠着的每一分钱负责,为每一个支持过我们的用户负责!”
这一场寒战,戴威难熬。
眼看他起高楼,眼看他宴宾客
回首戴威春风得意的伊始,作为一名90后,他在北大读硕士时便创办ofo,2016年完成五轮融资,一时名声大噪。
戴威相信,终有一天,ofo会和Google一样,影响世界。
2017年,ofo完成三轮融资,金额达10多亿美元。同年,戴威荣获《财富》中文版“中国40位40岁以下的商业精英”,他是榜上唯一一位90后。
2018年3月,ofo完成了E2-1轮融资,金额高达8.66亿美元。
一时风光无限的戴威是那个不打招呼抛弃我们的同龄人,而ofo成为共享单车的领跑者之一。
靠融资输血构成的大楼,崩塌是必然的
在ofo疯狂融资的背后,用烧钱发展起来的大流量,除了折腾广告位,并没有摸索出可持续盈利的模式。
仅靠资本输血的经营方式,大楼总得崩塌的。毕竟企业赚钱是重要的,生存是根本的。
正如马云曾批判“风口论”,很多小公司仅凭几个员工、几个故事就得到了几十亿美金的估值,这并不是好的现象。现在很少有公司能够越做越大、越做越好,因为很多人永远只相信赌博和All In。
曾有人问戴威:“你更在意事情本身能不能成功,还是谁把它做成功?”戴威说:“我把这件事情做成,比什么都重要。”
被光环笼罩的戴威在“赌”,在All In:他只想自己亲手做成,拒绝被收购。如果被他人收购,他宁愿做不成。过于年轻的他无法舍弃作为创始人的情怀和理想主义。
成也戴威,败也戴威。
毕竟对于企业来说,如无法一同成长,创始人体面退场不一定是坏事。这可从摩拜和哈罗单车被美团和阿里收购后,发展良好的现状体现。
吴晓波在《大败局》中如此建议创始人,“创始人需要十分理智地对自己拷问:企业今后的发展需要怎样的管理模式和管理者?在今后所有的企业需求中,什么是我今后最有能力为之提供的?我的兴趣和我的志向是什么,是否与企业长远发展真正吻合?”
199元的期待,还能要回来吗?
早在去年,据《财新周刊》爆料,截至当年12月1日,ofo动用30亿元用户押金,账面可能仅剩3.5亿元。
即便有相关部门立法,消费者的押金仍被企业任意挪用,且偿还艰难。在2017年11月,深圳市交通运输委提出未按规定时间退还押金和预付资金,由政府部门责令期限改正,并处以五万元以下罚款。
事实上如果企业有钱就能依法追回,如果没钱了普通大众也没办法了。
老赖,跑路,成为失败企业家的代名词。
乐视的贾跃亭曾信誓旦旦地承诺道,“会把金融机构、供应商以及任何欠款全部还上”。
后来贾跃亭成了大老赖,不管法院的判决,无视监管部门三番五令,全家跑路美国。在这一年多来,他在美国悠哉造起车来,不顾国内的水深火热。
彻底伤害了信任他的消费者,忽略追随他的员工。而成熟的企业家是勇于承担责任的:
当年巨人大厦倒塌,讨债人蜂拥而至之时,史玉柱承诺:“欠老百姓的钱一定要还。”正是出于这种“还债”的动力,史玉柱东山再起,且赚钱后的第一件事情就是还债。
CCTV中国经济年度人物给史玉柱的颁奖词是:第一次,他上演了一个成功的版本,第二次,他演绎了一个失败的案例;这一次,他从哪里跌倒就从哪里爬起,并完成了对企业家精神的定义。执着,诚信,勇于承担责任。
戴威作为90后创业的领跑者,让大家看到90后卓越的创业能力。未来始终属于年轻人的。
希望戴威能遵守自己的承诺“为欠着的每一分钱负责”,不要辜负消费者的信任,做个有担当的企业家。
起风了,唯有努力生存。
作者简介:五五,白天搬砖,晚上砌梦想。相信每个人有故事,程序员更是有许多事故,书写最接地气的程序员故事。
-End-
热 文 推 荐
☞ 刘强东无罪!
print_r('点个好看吧!');
var_dump('点个好看吧!');
NSLog(@"点个好看吧!");
System.out.println("点个好看吧!");
console.log("点个好看吧!");
print("点个好看吧!");
printf("点个好看吧!\n");
cout << "点个好看吧!" << endl;
Console.WriteLine("点个好看吧!");
fmt.Println("点个好看吧!");
Response.Write("点个好看吧!");
alert("点个好看吧!")
echo "点个好看吧!"
点击“阅读原文”,打开 CSDN App 阅读更贴心!



这次我们又整理了几个关于sequelize的使用技巧给大家,本次方向重点是多对多下的操作,还有sequelize的隐藏操作,整理不易希望大家多多点赞。
定义表结构
javascript 代码解读复制代码const { Sequelize, INTEGER, STRING, FLOAT, DATE, NOW, QueryTypes, Model } = require("sequelize");
const sequelize = new Sequelize({
dialect: "mysql",
database: "csdn", //你的数据库名称
username: "root",
password: "root", //你的数据库密码
host: "localhost",
port: "3306",
timezone: "+08:00", // 由于orm用的UTC时间,这里必须加上东八区,否则取出来的时间相差8小时
define: {
// 使用自定义的表名
freezeTableName: true,
// 自动生成时间戳 -小驼峰式
timestamps: true,
// 表名小驼峰
underscored: false,
},
attributeBehavior: "escape",
logging: true,
});
// 这次我们用兴趣班举例子 一个兴趣班可以有很多个学生 一个学生可以报很多兴趣班
const InterestClasses = sequelize.define(
"interest_classes",
{
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
name: { type: STRING, allowNull: false, comment: "兴趣班名称" },
money: { type: FLOAT, allowNull: false, comment: "费用" },
},
{ createdAt: false, updatedAt: false }
);
const Student = sequelize.define(
"student",
{
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
name: { type: STRING, allowNull: false, comment: "学生名称" },
},
{ createdAt: false, updatedAt: false }
);
// 连接表
const StudentInterestClass = sequelize.define(
"student_interest_class",
{
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
student_id: {
type: INTEGER,
allowNull: false,
comment: "学生id",
// 这种写法会直接创建外键 做表删除或重置操作的时候会报错
// references: { model: Student, key: "id" }
},
interest_class_id: { type: INTEGER, allowNull: false, comment: "兴趣班id" },
},
{ createdAt: false, updatedAt: false }
);
// 完美的多对多定义关系 以及中间表的一对多关系 constraints:false 去除约束 防止表创建的时候初始化外键 导致后续数据不好清除 但是外键也是提升查询速度的 由于我们数据量少 就不创建了
InterestClasses.belongsToMany(Student, { through: StudentInterestClass, constraints: false, foreignKey: "interest_class_id" });
Student.belongsToMany(InterestClasses, { through: StudentInterestClass, constraints: false, foreignKey: "student_id" });
InterestClasses.hasMany(StudentInterestClass, { foreignKey: "interest_class_id", constraints: false });
Student.hasMany(StudentInterestClass, { foreignKey: "student_id", constraints: false });
StudentInterestClass.belongsTo(Student, { foreignKey: "student_id", constraints: false });
StudentInterestClass.belongsTo(InterestClasses, { foreignKey: "interest_class_id", constraints: false });
// 初始化表
await sequelize.sync({ alter: true });
技巧1:批量创建学生数据时 直接关联已有数据项 创建到连接表中
javascript 代码解读复制代码 // 事务创建
const transaction = await sequelize.transaction();
// 数据清除
await sequelize.truncate({ force: true, transaction });
// 随机数
const randomFrom = (min, max) => {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
// 科目
let classes = ["语文", "数学", "英语"];
let creates = await InterestClasses.bulkCreate(
classes.map((item, index) => ({ id: index + 1, name: item, money: randomFrom(1000, 2000) })),
{ transaction }
);
// 创建出来的科目
creates = JSON.parse(JSON.stringify(creates));
// 传入数组 随机获取数组里面的1,length-1个元素
function randomArray(array) {
let length = array.length;
let randomLength = randomFrom(1, length - 1);
let result = [];
// 不拿到重复项
while (result.length < randomLength) {
let randomIndex = randomFrom(0, length - 1);
let item = array[randomIndex];
if (!result.includes(item)) {
result.push(item);
}
}
return result;
}
let students = [];
for (let i = 0; i < 10; i++) {
let interest_classes = randomArray(creates).map((item) => {
// 这里涉及到了关联创建 create的地方必须要include关联的模型
// interest_classes 我们定义的表 student_interest_class 连接表名 和我们上面define定义的一致
return { ...item, interest_classes: [{ student_interest_class: item.id }] };
});
students.push({ name: randomName(), interest_classes });
}
// console.log(students);
//小技巧:在bulkCreate中传入include可以直接将关联表的数据插入到数据库中 但是要注意的是 关联表的数据不能重复 否则会报错 所以我们要在bulkCreate中传入ignoreDuplicates: true 来忽略重复项
await Student.bulkCreate(students, { transaction, include: { model: InterestClasses, ignoreDuplicates: true } });
技巧2:直接获取到普通对象结果
javascript 代码解读复制代码 // 小技巧:获取表数据后可以直接使用JSON.parse(JSON.stringify(data))来将数据转换为普通对象 不做原数组的操作的话 可以直接返回该数组
// 为什么不能使用nest+raw呢 在findAll下使用 数组会变成 拆散的数据 返回n*m条 {id:1,name:'语文',money:1250,students:{id:1,name:xxx}}
const class_list = await InterestClasses.findAll({ include: { model: Student, through: { attributes: [] } }, transaction });
// [{
// id: 1,
// name: '语文',
// money: 1250,
// students: [ [Object], [Object], [Object], [Object], [Object] ]
// },...]
console.log(JSON.parse(JSON.stringify(class_list)));
// 小技巧:findOne下也不能使用raw:true+nest:true 因为findOne下只能返回一个对象 include里的数据只会有一条 所以不能使用nest:true
// 直接对对象上的toJSON方法就可以拿到正常对象
const student_list = await Student.findOne({ include: { model: InterestClasses, through: { attributes: [] } }, transaction });
// {
// id: 1,
// name: '谢明飞',
// interest_classes: [
// { id: 1, name: '语文', money: 1250 },
// { id: 2, name: '数学', money: 1300 }
// ]
// }
console.log(student_list.toJSON());
技巧3:劫持findAll方法 减少重复深拷贝写法
javascript 代码解读复制代码 // 发现没有我们每次都要JSON.parse(JSON.stringify(data))来将数据转换为普通对象
// 小技巧6:劫持原方法 根据条件返回是否要原始数组
let original = Model.findAll;
Model.findAll = async function (...args) {
let [options] = args;
let value = await original.apply(this, args);
return options && options.origin ? JSON.parse(JSON.stringify(value)) : value;
};
// [
// { id: 1, name: '谢明飞' },
// { id: 2, name: '何飞良' },
// { id: 3, name: '黄鹏涛' },
// { id: 4, name: '曹强良' },
// { id: 5, name: '唐鹏良' },
// { id: 6, name: '梁辉军' },
// { id: 7, name: '谢飞鹏' },
// { id: 8, name: '陈辉刚' },
// { id: 9, name: '胡震辉' },
// { id: 10, name: '曹健明' }
// ]
// console.log(await Student.findAll({ origin: true }));
技巧4:fn函数
javascript 代码解读复制代码 // 和我们上一章一样 但是findOne的时候就会报错 提示 interest_classes.money这行不存在
const student_cost = await Student.findAll({
origin:true,
attributes: ["name", [sequelize.fn("SUM", sequelize.col("interest_classes.money")), "cost"]],
include: { model: InterestClasses, through: { attributes: [] }, attributes: [] },
group: ["Student.id"],
});
// [
// { name: "谢明飞", cost: 2550 },
// { name: "何飞良", cost: 2550 },
// { name: "黄鹏涛", cost: 1418 },
// { name: "曹强良", cost: 1300 },
// { name: "唐鹏良", cost: 1418 },
// { name: "梁辉军", cost: 1300 },
// { name: "谢飞鹏", cost: 2718 },
// { name: "陈辉刚", cost: 2550 },
// { name: "胡震辉", cost: 2550 },
// { name: "曹健明", cost: 1250 },
// ];
console.log(student_cost);
// Unknown column 'interest_classes.money' in 'field list'
// 解决方案:加上where条件的id
const student_cost_one = await Student.findOne({
attributes: ["name", [sequelize.fn("SUM", sequelize.col("interest_classes.money")), "cost"]],
include: { model: InterestClasses, through: { attributes: [] }, attributes: [] },
group:["Student.id"]
});
console.log(student_cost_one);
// 不加where的语句就会出现这个样的查询方式 FROM 里面取了一条数据 然后再去关联表里面取数据 我们对attributes编写的fn函数位置不对了
// 源码sequelize/model.js 1236行 当findOne 无where 或者where里没有 primaryKey uniqueKeys 时 会为 limit=1 因为是先深拷贝的options 所以我们后写的limit也无用
// SELECT
// `student`.*
// FROM
// (
// SELECT
// `student`.`id`,
// `student`.`name`,
// SUM(`interest_classes`.`money`) AS `cost`
// FROM
// `student` AS `student`
// LIMIT 1
// ) AS `student`
// LEFT OUTER JOIN (
// `student_interest_class` AS `interest_classes->student_interest_class`
// INNER JOIN `interest_classes` AS `interest_classes` ON `interest_classes`.`id` = `interest_classes->student_interest_class`.`interest_class_id`
// ) ON `student`.`id` = `interest_classes->student_interest_class`.`student_id`
const right_student_cost_one = await Student.findOne({
where: {
id: 1,
},
attributes: ["name", [sequelize.fn("SUM", sequelize.col("interest_classes.money")), "cost"]],
include: { model: InterestClasses, through: { attributes: [] }, attributes: [] },
});
// { name: '谢明飞', cost: 2550 }
console.log(right_student_cost_one.toJSON());
技巧5:literal函数做计算操作
javascript 代码解读复制代码 // 通过literal计算出该兴趣班报名的总报名费 literal在属性上的操作 是完全自由的 可以使用任何函数 甚至叠加函数 插入查询等
let class_cost = await InterestClasses.findAll({
origin:true,
attributes: [
"name",
"money",
[sequelize.literal(`count(students.id) * interest_classes.money`), "total_money"],
[sequelize.fn("count", sequelize.col("students.id")), "count"],
],
include: { model: Student, through: { attributes: [] }, attributes: [] },
group: ["interest_classes.id"],
});
// [
// { name: '语文', money: 1250, total_money: 6250, count: 5 },
// { name: '数学', money: 1300, total_money: 9100, count: 7 },
// { name: '英语', money: 1418, total_money: 4254, count: 3 }
// ]
console.log(class_cost);
技巧7:反复使用的原始查询转换为视图 再使用模型映射
javascript 代码解读复制代码 // 我们之前遇到原始语句才能做到的事情 如果反复调用 那要封装起来 或者还有新的查询条件的时候 又要修改原方法
// 小技巧:视图操作 其实sequelize支持对视图进行查询的操作且允许各种条件查询 但是要注意的是 视图是不能进行修改的
// 需求:获取每个科目最新报名的人
// 当这种情况出现的时候 正常思路是 通过StudentInterestClass去groupby interest_class_id 然后order by
let lastest_student = await StudentInterestClass.findAll({
group: ["interest_class_id"],
order: [["id", "desc"]],
include: [
{ model: Student, attributes: ["name"] },
{ model: InterestClasses, attributes: ["name"] },
],
origin: true,
});
// 发现查询结果达不到要求
// [
// {
// id: 5,
// student_id: 3,
// interest_class_id: 3,
// student: { name: '黄鹏涛' },
// interest_class: { name: '英语' }
// },
// {
// id: 2,
// student_id: 1,
// interest_class_id: 2,
// student: { name: '谢明飞' },
// interest_class: { name: '数学' }
// },
// {
// id: 1,
// student_id: 1,
// interest_class_id: 1,
// student: { name: '谢明飞' },
// interest_class: { name: '语文' }
// }
// ]
console.log(lastest_student);
// 进行视图创建
await sequelize.query(
"CREATE OR REPLACE VIEW join_view AS SELECT b.id, student_id, interest_class_id, student.`name` AS `student_name`, interest_class.`name` AS `subject_name`, interest_class.`money` AS `money` FROM (SELECT *, ROW_NUMBER() OVER (PARTITION BY interest_class_id ORDER BY id DESC) AS rn FROM `student_interest_class` AS r) AS b LEFT OUTER JOIN `student` AS `student` ON `b`.`student_id` = `student`.`id` LEFT OUTER JOIN `interest_classes` AS `interest_class` ON `b`.`interest_class_id` = `interest_class`.`id`"
);
// 防止重复调用query的情况下 我们可以创建视图 再通过模型去绑定视图 这样就可以直接使用模型的方法来查询了
// CREATE OR REPLACE VIEW join_view AS
// SELECT
// b.id,
// student_id,
// interest_class_id,
// student.`name` AS `student_name`,
// interest_class.`name` AS `subject_name`,
// interest_class.`money` AS `money`
// FROM (
// SELECT
// *, ROW_NUMBER() OVER (
// PARTITION BY interest_class_id
// ORDER BY id DESC
// ) AS rn
// FROM `student_interest_class` AS r
// ) AS b
// LEFT OUTER JOIN `student` AS `student` ON `b`.`student_id` = `student`.`id`
// LEFT OUTER JOIN `interest_classes` AS `interest_class` ON `b`.`interest_class_id` = `interest_class`.`id`;
// 创建视图模型
const JoinView = sequelize.define(
"join_view",
{
id: { type: INTEGER, primaryKey: true, autoIncrement: true },
student_id: { type: INTEGER, allowNull: false },
interest_class_id: { type: INTEGER, allowNull: false },
student_name: { type: STRING, allowNull: false },
subject_name: { type: STRING, allowNull: false },
money: { type: FLOAT, allowNull: false },
},
{ timestamps: false }
);
// [
// {
// id: 15,
// student_id: 10,
// interest_class_id: 1,
// student_name: '曹健明',
// subject_name: '语文',
// money: 1250
// },
// {
// id: 14,
// student_id: 9,
// interest_class_id: 2,
// student_name: '胡震辉',
// subject_name: '数学',
// money: 1300
// },
// {
// id: 9,
// student_id: 7,
// interest_class_id: 3,
// student_name: '谢飞鹏',
// subject_name: '英语',
// money: 1418
// }
// ]
// 视图方便了我们做的查询操作 但是不能完全依赖视图 视图毕竟是通过语句生成的 不如原表操作速度块 为了效率 有时候我们可以牺牲空间来转换 下次我们讲讲钩子
console.log(await JoinView.findAll({ origin: true, group: ["subject_name"] }));
这次的分享到这里就结束了,祝愿大家越变越强,工资up up up
评论记录:
回复评论: