How we remove null error encounter in referencing node js mongodb - javascript

I have to use populate method for referencing my second collection. I have two collections one is levels and second child.
I have referenced to my level collection through child collection. For this, I use the populated method but it returns null.
This is node js code
function(){
var query = {'_id': result._id };
var params = 'usercurrLevelId';
childQuizInfo.findOne(query, params).populate({
path : 'usercurrLevelId',
model : 'Level',
select : '_id level_num age'
}).exec(function(err,levelinfo){
if(err) return next(err);
res.send(levelinfo);
});
}
This level schema
var LevelSchema = new Schema({
_id: { type: String },
age: { type: Number },
level_num: { type: Number },
min_score: { type: Number },
max_questions: { type: Number }
});
var Level = mongoose.model('Level', LevelSchema);
This is child schema
usercurrLevelId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Level',
index: true
}
This is the level stored in mongoDB
{
"_id" : ObjectId("57cb1ef8b0b05a2ce9b0c24b"),
"age" : 5,
"level_num" : 1,
"min_score" : 12,
"max_questions" : 30
}
{
"_id" : ObjectId("57cb1ef9b0b05a2ce9b0c24c"),
"age" : 5,
"level_num" : 2,
"min_score" : 15,
"max_questions" : 33
}
This is the child stored in mongoDB
{
"_id" : ObjectId("57cc0410d51045452644251b"),
"usercurrLevelId" : ObjectId("57cb1ef8b0b05a2ce9b0c24b")
}
And the output i get
{
"_id": "57cc0410d51045452644251b",
"usercurrLevelId": null,
"__v": 0
}
I using this node js query so that I get level_num and _id from my level schema using this referencing.

Related

How can I increment & add to array on mongoose

In my database, I have a user table with 2 columns: score & history :
I have another table called card containing some specific information & a card _id.
Each time a specific card is clicked, I would like the '/CardClicked' router to be called for :
Additional (increment) a specific number value (1.5) on score column
Add the cart _id value on the array of history column: (to save, which card the user clicked)
I wanted to have something like that in my database:
users:
{ "_id" : 1, "score" : 6.0, "history" : [ 62k6hf45b0af050fe, 69k5hf45b0af450fg, 65k5hf45b0af450fg, ]}
{ "_id" : 2, "score" : 4.5, "history" : [ 65k5hf45b0af450fg,] }
{ "_id" : 3, "score" : 10.0, "history" : [ 66k5hf45t0af930rp, 67k5hf45b0af450fg, 62k6hf45b0af050fe, 61y5hf884b0af450vb, ] }
But, idk why it doesn't update properly on columns, however i don't have any error, that my code i made it :
My UserSchema.js :
const mongoose = require('mongoose')
const UserSchema = new mongoose.Schema({
...
score: {
type: Number,
},
history: {
type: [String]
},
createdAt: {
type: Date,
default: Date.now,
},
})
module.exports = mongoose.model('User', UserSchema)
My router.js :
app.post('/CardClicked', async function (req, res){
console.log("User ID "+req.user._id, "Card ID : "+req.body._id);
try{
const condition = { _id: req.user._id };
//the req.body._id contain the card id from my front to send that to router
const putPostID = { $addToSet: { history: req.body._id }};
const additionalPoints = {$inc : { score : 1.5 }};
await User.findOneAndUpdate(condition, additionalPoints, putPostID, {upsert: true})
}catch(err){
res.status(500).send({error: err })
}
});
Every update operation must go into one object. In your case:
User.findOneAndUpdate(condition, {
$inc: { score: 1.5 },
$addToSet: { history: req.body._id },
},
{ upsert: true },
)

how to avoid duplicate key error collection in mongodb

i want to build a cart for my website, this is the schema for the cart:
const productSchema = require("./product")[1];
const cartItemSchema = new Schema<CartItem>(
{
product: productSchema,
quantity: {
type: Number,
required: true,
min: [1, "Quantity can not be less then 1."],
},
},
{
timestamps: true,
}
);
const CartSchema = new Schema(
{
userID: {
type: Schema.Types.ObjectId,
ref: "User",
},
items: [cartItemSchema],
},
{ timestamps: true }
);
module.exports = model<Cart>("Cart", CartSchema);
the problem is, when I add a product in a specific user cart, while the same product is allready added to another user cart document, I get this error:
"message":"cannot add to cart E11000 duplicate key error collection: elec-store.carts index: items.productID_1 dup key: { items.productID: null }, stack: MongoError: E11000 duplicate key error collection: elec-store.carts index: items.productID_1 dup key
this is the add function
public async add(cartItem: CartItem, userID: string): Promise<Cart> {
let cartInDB = null;
await CartModel.findOne({ userID: userID }, (err, cart) => {
cartInDB = cart;
});
if (AppUtils.hasValue(cartInDB)) {
const index = cartInDB.items.findIndex(
(item) => item.product._id.toString() === cartItem.product._id
);
if (index !== -1) {
cartInDB.items[index].quantity =
cartInDB.items[index].quantity + cartItem.quantity;
cartInDB.items[index].product._id = cartItem.product._id;
const cartAfterAdding = await cartInDB.save();
return cartAfterAdding;
} else {
await CartModel.update(
{ _id: cartInDB._id },
{ $push: { items: cartItem } }
);
}
return cartInDB;
} else {
const itemsArray: CartItem[] = [];
itemsArray.push(cartItem);
let createdCart = new CartModel({
userID: userID,
items: itemsArray,
});
await createdCart.save(); \\ this is where the problem occurs
return createdCart;
}
}
and this is how my cart looks like in mongodb document:
db.carts.find().pretty()
{
"_id" : ObjectId("60ea9fb81b2b4c048c3b1544"),
"userID" : ObjectId("60dee5e1da81bd274cd304de"),
"items" : [
{
"_id" : ObjectId("60ea9fb81b2b4c048c3b1545"),
"product" : {
"_id" : ObjectId("60e62cb21f74572b7c0b3a30"),
"name" : "tv",
"description" : "the best tv",
"categoryID" : 2,
"quantity" : "2",
"serialNumber" : "226swaq12",
"price" : 2000,
"imgUrl" : "https://www.seekpng.com/png/full/774-7744281_samsung-electronics-samsung-electronic-product-png.png"
},
"quantity" : 6,
"createdAt" : ISODate("2021-07-11T07:37:29.790Z"),
"updatedAt" : ISODate("2021-07-11T07:38:15.583Z")
},
{
"_id" : ObjectId("60eaa16b1b2b4c048c3b155d"),
"product" : {
"_id" : ObjectId("60e066009be1060748201ad3"),
"name" : "samsung tv",
"description" : "the best tv",
"quantity" : "2",
"categoryID" : 2,
"serialNumber" : "2212",
"price" : 2000,
"imgUrl" : "https://www.seekpng.com/png/full/774-7744281_samsung-electronics-samsung-electronic-product-png.png"
},
"quantity" : 9,
"updatedAt" : ISODate("2021-07-11T07:46:19.313Z"),
"createdAt" : ISODate("2021-07-11T07:44:43.764Z")
}
],
"createdAt" : ISODate("2021-07-11T07:37:29.792Z"),
"updatedAt" : ISODate("2021-07-11T07:46:19.314Z"),
"__v" : 0
}
I use mongoose.Schema to create new schemas and then when making reference to a different schema I do it like this:
product: { type: mongoose.Schema.Types.ObjectId, ref: 'product' },
If later you need to show also the product info (db.carts.find()), you can use populate() to replace the reference for all the product entries.
You can use upsert true.
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ],
hint: <document|string> // Available starting in MongoDB 4.2
}
)
For example -
db.books.update(
{ item: "ZZZ135" }, // Query parameter
{ // Replacement document
item: "ZZZ135",
stock: 5,
tags: [ "database" ]
},
{ upsert: true } // Options
)
This may help: Mongo Update

How to get array length instead of full array in find()?

I have a mongodb (using mongoose) collection ("items") which includes an array ("images") among its properties. Some example documents:
[
{
"_id" : ObjectId("543fa67e9672ec37ebe3d026"),
"name" : "Alice",
"images" : [
{ url: "http://images.com/1.jpg" },
{ url: "http://images.com/2.jpg" },
{ url: "http://images.com/3.jpg" },
]
},
{
"_id" : ObjectId("543fa67e9672ec37ebe3d027"),
"name" : "Bob",
"images" : [
{ url: "http://images.com/4.jpg" },
{ url: "http://images.com/5.jpg" },
]
},
]
I want to implement a query which returns - along with other document properties - the array length (and not the array contents). I know I can get the array length with
db.items.aggregate([
{ "$project" : { "_id" : 0, "imagesLength" : { "$size" : "$images" } } }
])
But I need the imagesLength values along with the documents returned with a find:
db.items.findMany(
{ ...filter },
{ name: 1, imagesCount: 1 }
);
The question is: how can I get the array length along with the find results ?
You can do same as aggregation projection in find's second argument,
Starting in MongoDB 4.4, as part of making find projection consistent with aggregation’s $project stage,
db.items.find(
{ ...filter },
{
_id: 0,
name: 1,
images: { $size: "$images" }
})
Playground
You can add a match stage at first in your aggregation to filter the results. Then you can project all fields needed and generate the new ones.
db.items.aggregate([
{ "$match" : { ...filter },
{ "$project" : { "imagesLength" : { "$size" : "$images" }, "name": 1 } }
])

Mongoose create a new document with catergorized sub documents

I've been going through the Mongoose docs, and I think I'm missing some fundamental understanding in how it works.
What I'm trying to do
I'm making a third party API call that returns a structure that looks like
Route
|__Train 1 on Route
|__Upcoming Station (with ID)
| |__Time to this station
|__Upcoming Station (with ID)
| |__Time to this station
...
|__Train 2
...
And my goal is to format it in a document as such
tableId : String,
stations : [{
stopId : String,
incoming : [{
vehicleId : String,
timeAway : { type: Number, min: 0, max: 3000 },
lastUpdated : { type: Date, default: Date.now }
}]
}],
What I'm trying currently is going through the received data for each train, and in that each upcoming station, and plug the estimated arrival time into the list of stations. The important part is that Train 1 and Train 2 may both be arriving at a given station, and I only want one station element with multiple predictions. The problem is, I can't do a findOneAndUpdate with an upsert, as the document doesn't exist yet.
From the doc on subdocs (here), I've tried push and addToSet, but these just create a subdocument for each prediction. For example I'll get:
[{
stopId: 1234,
incoming : [{
vehicleId : 11,
timeAway : 200
}]
},
stopId: 1234,
incoming : [{
vehicleId : 22,
timeAway : 400
}]
}]
Where I'm trying to get:
[{
stopId: 1234,
incoming : [{
vehicleId : 11,
timeAway : 200
},{
vehicleId : 22,
timeAway : 400
}]
}]
I feel like I'm missing some fundamental aspect of creating this document.
For data schema,
var StationSchema = new mongoose.Schema({
tableId: String,
stations: [{
stopId: String,
incoming: [{
vehicleId: String,
timeAway: {type: Number, min: 0, max: 3000},
lastUpdated: {type: Date, default: Date.now}
}]
}]
});
Save data through
var s = new Station({
tableId: '2'
});
s.save(function(err) {
Result
{ "_id" : ObjectId("56e68bcf851a00680832ef13"), "tableId" : "2", "stations" : [ ], "__v" : 0 }
We know the default value of stations is empty array, which is design behavior of mongoose. The upsert: true will add one new document not for sub-document.
To insert station subdocument, we can first check whether the stopId exists, if not, insert new station subdocument. otherwise, we can insert new incoming subdocument into stations. Here are sample codes
Station
.findOneAndUpdate({tableId: '2', 'stations.stopId': {$exists: false}},
{$addToSet: {stations: {stopId: '1234', incoming: []}}},
function (err, doc){
if (err)
console.log(err);
else{
Station
.findOneAndUpdate(
{'stations.stopId': 1234},
{$addToSet: {'stations.$.incoming': {vehicleId: 22, timeAway: 400}}},
function(err, doc) {
if (err)
console.log(err);
else
console.log(doc);
});
}
});

Mongoose DBrefs - Cast to ObjectId failed for value

I have a Team Schema holding details about teams, and a Match Schema to store these teams in. I am trying to make it so that the home/away teams in the Match Schema are references to the Team object. I have put my code below, I'm getting an error when saving the Team but I can't help but feel I have done something wrong with the Schema's or the saving of the Match. Can anyone help?
So far I have the following code:
Team.js extract
var Team = new Schema({
'key' : {
unique : true,
type : Number,
default: getId
},
'name' : { type : String,
validate : [validatePresenceOf, 'Team name is required'],
index : { unique : true }
}
});
module.exports.Schema = Team;
module.exports.Model = mongoose.model('Team', Team);
Match.js extract
var util = require('util');
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var Team = require('../schemas/Team').Schema;
var Match = new Schema({
'key' : {
unique : true,
type : Number,
default: getId
},
'hometeam' : {
type : Schema.ObjectId,
ref : 'Team'
},
'awayteam' : {
type : Schema.ObjectId,
ref : 'Team'
}
});
module.exports = mongoose.model('Match', Match);
index.js
app.get('/match', function(req, res) {
var key = 1356136550152; // Reading
Team.findByKey(key, function(err, team) {
if(err) {
res.send("An error occured");
}
if(!team) {
res.send("The team does not exist");
}
var match = new Match();
match.hometeam = team;
match.save(function(err) {
if(err) {
util.log('Error while saving Match: ' + util.inspect(err));
res.send("An error occured whilst saving the match");
} else {
res.send("Saved the match");
}
});
});
});
ERROR:
Error while saving Match: { message: 'Cast to ObjectId failed for value "{ name: \'testTeam\',\n _id: 50d500663ca6067226000001,\n __v: 0,\n key: 1356136550152 }" at path "hometeam"',
name: 'CastError',
type: 'ObjectId',
value:
[ { name: 'testTeam',
_id: 50d500663ca6067226000001,
__v: 0,
key: 1356136550152 } ],
path: 'hometeam' }
Error with team._id
Error while saving Match: { [MongoError: E11000 duplicate key error index: testdb.matches.$team.name_1 dup key: { : null }]
name: 'MongoError',
err: 'E11000 duplicate key error index: testdb.matches.$team.name_1 dup key: { : null }',
code: 11000,
n: 0,
connectionId: 8,
ok: 1 }
db.matches.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "testdb.matches",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"key" : 1
},
"unique" : true,
"ns" : "testdb.matches",
"name" : "key_1",
"background" : true,
"safe" : null
},
{
"v" : 1,
"key" : {
"team.key" : 1
},
"unique" : true,
"ns" : "testdb.matches",
"name" : "team.key_1",
"background" : true,
"safe" : null
}
]
In index.js it should be:
match.hometeam = team._id;
instead of:
match.hometeam = team;
UPDATE
Regarding the new error message, it looks like you have a unique index on the matches collection that refers to fields that don't exist. Drop it in the shell using:
db.matches.dropIndex('team.name_1')

Categories