问题
I know the title is confusing but let me explain more clearly.
Here is what my mongoose schema looks like:
var LocationSchema = new Schema({
locationKey: {type: String, unique: true},
wheat: Array,
barley: Array,
cty: {type: String, unique: true},
twp: {type: String, index: { unique: true} , dropDups: true},
rge: {type: String, unique: true},
});
I wrote some code that will create 3500 locations using this schema. The problem is that lots of locations have the same value for twp. When this is the case, I need it to still create the object, but not create the twp if any other object that has been created has the same twp.
As you can see above I tried using the unique approach above. Here is two sample objects for more clarity:
Object One:
{
"_id" : ObjectId("56f5af9547a341720b0b25cd"),
"rge" : "034E",
"twp" : "001N",
"cty" : "003",
"locationKey" : "003001N034E",
"__v" : 0
}
If I am going to create a new object, that has twp: 001N, I would like it to be created, but to look like so:
{
"_id" : ObjectId("56f5af9547a341720b0b25cd"),
"rge" : "034W",
"cty" : "004",
"locationKey" : "003001N034E",
"__v" : 0
}
In server JS I have an array of 3,000 objects, I am looping through this array to create a Location Object for each item like so:
locations.forEach(function(item){
var location = new Location();
location.locationKey = item.locationKey.trim();
location.cty = item.cty.trim();
location.twp = item.twp.trim();
location.rge = item.rge.trim();
location.wheat = item.wheat;
location.barley = item.barley;
location.save();
});
回答1:
To add methods pre creating schema, you could do it through schema.queue per this discussion, here are the test codes under mongoose v4.4.6
var twpSet = new Set();
LocationSchema.methods.twp1 = function () {
var curTwp = this.twp;
if (twpSet.has(curTwp)) {
this.twp = undefined; // remove the twp field once duplicated
} else {
twpSet.add(curTwp); // save the existing twp value
}
};
LocationSchema.queue('twp1');
Test data
var l1 = new Loca({
locationKey: 'k1',
cty: 'c1',
twp: 't1',
rge: 'r1'
});
console.log(l1);
l1.save(function(err) {
if (err)
console.log(err);
else
console.log('save location1 successfully');
})
var l2 = new Loca({
locationKey: 'k2',
cty: 'c2',
twp: 't1',
rge: 'r2'
});
console.log(l2);
l2.save(function(err) {
if (err)
console.log(err);
else
console.log('save location2 successfully');
})
Results are
{ "_id" : ObjectId("56f5e484a22885dd0362a39a"), "locationKey" : "k1", "cty" : "c1", "twp" : "t1", "rge" : "r1", "barley" : [ ], "wheat" : [ ], "__v" : 0 }
{ "_id" : ObjectId("56f5e484a22885dd0362a39b"), "locationKey" : "k2", "cty" : "c2", "rge" : "r2", "barley" : [ ], "wheat" : [ ], "__v" : 0 }
Another option is to check the existing document before save the new document through .pre('save' middleware, if find the duplicate twp, remove it in the new document, then save it.
LocationSchema.pre('save', function(next) {
var curTwp = this.twp;
console.log(curTwp);
var obj = this;
Loca.findOne({twp: curTwp}, function(err, loc) {
if (err)
next(err);
else if (loc) {
// find the duplicate twp before save
obj.twp = undefined;
next();
}else
next();
})
});
var Loca = mongoose.model('Loca', LocationSchema);
Test codes
var l1 = new Loca({
locationKey: 'k1',
cty: 'c1',
twp: 't1',
rge: 'r1'
});
var l2 = new Loca({
locationKey: 'k2',
cty: 'c2',
twp: 't1',
rge: 'r2'
});
console.log(l1);
l1.save(function(err) {
if (err)
console.log(err);
else {
l2.save(function(err) {
if (err)
console.log(err);
else
console.log('save location2 successfully');
})
}
})
Save result as above, to make sure your huge data is saved one by one, you could use async.series.
来源:https://stackoverflow.com/questions/36230055/mongoose-needs-to-create-objects-but-skip-the-property-if-another-object-alread