Why duplicates are save even if I use compound index? Mongo(Mongoose) - node.js

I am trying to save click coordinates on database but if x and y are the same I don't want to save them. Even if I use compound index and do everything by book, it still saves everything. There is similar question on stackoverflow but it doesn't work for my code.
Model, Schema:
var mongoose = require('mongoose');
var uniqueValidator = require('mongoose-unique-validator');
require('mongoose-double')(mongoose);
var Schema = mongoose.Schema;
var integerValidator = require('mongoose-integer');
var SchemaTypes = mongoose.Schema.Types;
var clickPoint = new Schema({
clicks: [
{
x: {
type: SchemaTypes.Double
},
y: {
type: SchemaTypes.Double
},
value: {
type: Number,
integer: true
}
}
]
});
clickPoint.index({x: 1, y: 1}, {unique: true});
clickPoint.plugin(integerValidator);
clickPoint.plugin(uniqueValidator);
//export model...
module.exports = mongoose.model("ClickPoint", clickPoint);
Model Controller:
var ClickPoint = require('../Models/point');
exports.addPoint = function (click) {
ClickPoint.findOne(function (err, data) {
if(!err) {
if(data) {
data.clicks.push({
x: click.x,
y: click.y,
value: click.value
});
data.save();
}
else {
var entry = new ClickPoint({
x: click.x,
y: click.y,
value: click.value
});
entry.save();
}
}
})
};
Could it be that all the records are stored in an array and as far as I know, index allows to store duplicates in array? If that is the problem than how would I keep objects unique in an array.

You index x & y, while the fields are clicks.x & clicks.y. If you're trying to add unique values to an array, why not use addToSet?

Related

NodeJS Mongoose update document

I'm trying to update or create a document in a MongoDB collection, using "mongoose" this way :
this.statsModel.findOne(
{product_id: requestData.ean},
).then((stats: mongoose.Schema) => {
const productId: string = requestData.ean;
// Update stats with the new scan...
const beforeStats: mongoose.Schema = stats;
const scan: any = {
coords: {
lat: requestData.lat,
lon: requestData.lon,
},
at: new Date(),
};
if (stats) {
stats.scans.push(scan);
stats.update();
} else {
const newStat = new this.statsModel();
newStat._id = requestData.ean;
newStat.product_id = requestData.ean;
newStat.scans = [scan];
newStat.purchases = [];
newStat.save();
}
When this code runs, no new element appears in the "scans" property if had a stats document.
The document is properly created if the stats document was not found.
I tried to change "update()" method to "save()" method, but, this way, i got a "Version error No matching document for the id..."
What i'm doing wrong ?
Regards...
Finally, update the type of the stats promised to Model instead of mongoose.Schema :
this.statsModel.findOne(
{product_id: requestData.ean},
).then((stats: Model<Stats>) => {
const productId: string = requestData.ean;
// Update stats with the new scan...
const beforeStats: mongoose.Schema = stats;
const scan: any = {
coords: {
lat: requestData.lat,
lon: requestData.lon,
},
at: new Date(),
};
if (stats) {
stats.scans.push(scan);
stats.save();
} else {
const newStat = new this.statsModel();
newStat._id = requestData.ean;
newStat.product_id = requestData.ean;
newStat.scans = [scan];
newStat.purchases = [];
newStat.save();
}
So the save() method properly works...
Thx

How to save multiple items in array to database in NodeJS/Mongoose

So first of all im getting a post via a form that returns to me multiple lines of text
then i use the following to split it into multiple urls
var str = req.body.url;
var split = str.split('\n');
then i get this
[urlone,urltwo,urlthree]
my save function works fine for one document
i just cant seem to submit all three at the same time to mongo via mongoose commands .
ive tried a few forEach loops . and got no help
I can really use some help here
I'm really new to nodejs
Define Model:
let mongoose = require('mongoose');
let Schema = mongoose.Schema;
let ModelSchema = new Schema(
{
property: String,
urls: []
},
{
collection: 'models',
strict: true,
autoIndex: true
}
);
module.exports = Model = mongoose.model('Model', ModelSchema);
Now, you can create or update any record.
let urlArray = req.body.url.split('\n');
// solution 1
let myModel = new Model();
myModel.property = 'xxx';
myModel.urls = urlArray;
myModel.save();
// solution 2
Model.update({ property: 'xxxx' }, { $set: { urls: urlArray } }, { upsert: true }, function(err, res) {
// continue to check err/res
})
// solution 3, prevent from duplicate entries
Model.update({ property: 'xxxx' }, { $addToSet: { urls: urlArray } }, { upsert: true }, function(err, res) {
// continue to check err/res
})

Mongoose: $inc not working

I am not sure what the problem is, as I've read numerous examples.
Taken from what I was advised here in this StackOverFlow(Mongoose - Increment a value inside an array of objects), I changed the format of poll at ease to accommodate what was recommended.
So I was able to create a document format as so:
{
"_id": "584c4160b3b22e1bdad59bce",
"title": "Food",
"description": "test",
"labelOptions": {
"burger": 29,
"coffee": 44,
"pizza": 23
},
"date": "Dec 10, 2016",
"__v": 0
}
Here's what I have so far:
Poll Model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const pollData = new Schema({
title: String,
description: String,
labelOptions: {},
date: String
})
module.exports = mongoose.model('PollData', pollData)
Using express and mongoose, here's what I have:
app.put('/polls/:id', function(req, res){
let id = req.params.id;
let labelOption = req.query.labelOption;
let query = `labelOptions.${labelOption}`
Poll.findByIdAndUpdate(
id,
{$inc: { query: 1 } },
function(err, document){
console.log(err)
console.log(document)
}
)
})
In my terminal, I see that console.log(document it receives the document I was looking for but it does not update the value at all.
Am I setting up the Model correctly? Or does Mongoose does not support template strings?
***update
This is snippet of how I am creating documents
let labelOptions = {}; <=== creating object literal to hold as placeholder
const title = req.body.title;
const description = req.body.description;
req.body.labelOptions.split(/,\s*/).map( prop =>{
labelOptions[prop] = 0 // set counter to default 0
})
const poll = new Poll({
title: title,
description: description,
labelOptions: labelOptions,
date: moment().format('MMM D, YYYY')
});
poll.save(function(err) {
if (err) { return next(err); }
res.json({ message : 'Poll added!'})
});
After doing some research across the internet, I found the reason why it wasnt working: You can't initialize objects with 'dynamic' keys.
Source: Mongoose update on a string variable not working?
By knowing that, it was just a simple solution to initialize an literal object as so:
let id = req.params.id;
let labelOption = req.query.labelOption;
let query = "labelOptions." + labelOption
let obj = {
[query] : 1
}
Poll.findByIdAndUpdate(
id,
{$inc: obj },
function(err, document){
console.log(err)
console.log(document)
}
)

how use Schema methods in mongoose sub-documents after loading

I have the following scheme in the mongoose
var Schema = mongoose.Schema;
var CellSchema = new Schema({
foo: Number,
});
CellSchema.methods.fooMethod= function(){
return 'hello';
};
var GameSchema = new Schema({
field: [CellSchema]
});
if create new document like:
var cell = new CellModel({foo: 2})
var game = new GameModel();
game.field.push(cell);
game.field[0].fooMethod();
it's correctly work. But if you run this code:
GameModel.findOne({}, function(err, game) {
console.log(game);
game.field[0].fooMethod()
})
i get TypeError: game.field[0].fooMethod is not a function
and console log is
{
field:
[ { foo: 2,
_id: 5675d5474a78f1b40d96226d }
]
}
how correct load sub-document with all schema methods?
You have to define the methods on the embedded schema before defining the parent schema.
Also you have to reference CellSchema instead of 'Cell'
var CellSchema = new Schema({
foo: Number,
});
CellSchema.methods.fooMethod = function() {
return 'hello';
};
var GameSchema = new Schema({
field: [CellSchema]
});

Shorter way for find() query

I want to find if cell with provided coordinates exists in DB.
Is there a shorter way to create this query?
var schema = new mongoose.Schema({
coors: {
x: String,
y: String
}
});
// coors = {x:'1', y:'2'};
schema.statics.is_cell_exists = function (coors, callback){
var Cell = this;
var coors_x = {};
var coors_y = {};
coors_x['coors'] = {x: coors.x};
coors_y['coors'] = {y: coors.y};
var query = { $and: [coors_x, coors_y] };
Cell.find( query ).exec(...);
};
It just seems you have some unnecessary variables, etc. You can simply use dot notation to get inside that "coors" object and search on it.
Cell.find({ $and : [{ 'coors.x' : coors.x }, { 'coors.y' : coors.y }] })

Resources