cant insert record with reference to another record - node.js

I have two models: platform and place (platform and place on platform)
platform
{
name: {
required: true,
unique: true,
type: String,
empty: false
},
description: {
required: false,
type: String,
empty: true
}
}
place
{
name: {
required: true,
type: String,
empty: false
},
platform: new Mongoose.Schema({
type: Mongoose.Schema.Types.ObjectId,
ref: PlatformSchema
})
}
The name of platform must be unique. First, I generate list of platforms. Then trying generate list of places on this platforms and receive error.
WriteError({
"code": 11000,
"index": 1,
"errmsg": "E11000 duplicate key error collection: test.places index: platform.ref.name_1 dup key: { : null }",
"op": {
"_id": "5b7ea477798f9c41f81c0234",
"name": "top",
"platform": {
"_id":"5b7ea41b878b4a41abcfc952"
}
}
})
Receive it until unique index for "name" field exists in platform schema.
I try insert place many ways:
PlaceRecord.insertMany([
{
name: "top",
platform: platformDocumentInstance
}
])
or
PlaceRecord.insertMany([
{
name: "top",
platform: platformDocumentInstance
}
])
or
PlaceRecord.insertMany([
{
name: "top",
platform: platformDocumentInstance
}
])
But result is same one. Note first record of place success inserted, but next record of place throw the exception. Please help.

It seems the document that you are inserting first has inserts null as platform.ref.name and when you insert second document your index platform.ref.name_1 fails because there is already a record with null.

Related

Sequelize included Model result keys are strings

Forgive my limited knowledge im about a week into using Sequelize,
Models.PlannerModel.Builds.findAll({
raw: true,
where: {
ProposedDelivery: { [Op.gt]: moment().format("YYYY-MM-DD") },
description: { [Op.ne]: null },
description: { [Op.ne]: " " },
description: { [Op.not]: null },
},
include: [
{
model: Models.PlannerModel.Unit,
required: true
},
],
the result from the above is as you would expect except all the keys for the fields in the includes are as strings so referencing them in my Pug template/class has to be done with brackets
overall not the end of the world just wondering if im doing something wrong ?
Cheers!
Turn off raw to get nested model objects and also to get plain objects use get({ plain: true}) for each returned model instance:
const builds = await Models.PlannerModel.Builds.findAll({
where: {
ProposedDelivery: { [Op.gt]: moment().format("YYYY-MM-DD") },
[Op.and]: [{
description: { [Op.ne]: null },
}, {
description: { [Op.ne]: " " },
}, {
description: { [Op.not]: null },
}
]
},
include: [
{
model: Models.PlannerModel.Unit,
required: true
},
]
})
const plainBuilds = builds.map(x => x.get({ plain: true }))
Please pay attention that I changed conditions with description. In your version of conditions only the last one will work because JS saves only the last key if there are several same keys in the same object.

Is there a way to validate a UUID inserted in a mongoDB using mongo's validator?

I am using migrate-mongo for managing my database migration and I am trying to create a new migration that create a collection with a validator and insert values in it. I want to use a UUID for the _id property and I am using the uuid-mongodb library to generate it. My problem is that I am not able to set the bsonType of my _id in the validator without causing the data insertion failure. Is there any way to make sure that the id of the documents inserted in the collection is a UUID? I know that mongoose could help me to solve this issue, but I would like the validation to be done at the database level. Also, when I do not specify the _id's bsonType in the validator, the insertion works, it fails validation only when I specify it.
Here is my migration code
const MUUID = require("uuid-mongodb");
module.exports = {
async up(db) {
//Will use https://docs.mongodb.com/manual/tutorial/model-tree-structures-with-materialized-paths/
await db.createCollection("itemCategories", {
validator: {
$jsonSchema: {
required: ["name"],
bsonType: "object",
properties: {
_id: {"object"}, //I also tried with binData
name: {
bsonType: "string",
maxLength: 50,
},
path: {
bsonType: ["string", "null"],
pattern: "^,([^,]+,)+$"
}
},
additionalProperties: false,
}
},
});
await db.collection("itemCategories").createIndex({"name": 1}, {unique: true});
await db.collection("itemCategories").insertMany([
{_id: MUUID.v4(), name: "Sport", path: null},
{_id: MUUID.v4(), name: "Tool", path: null},
{_id: MUUID.v4(), name: "Entertainment", path: null}
]);
},
async down(db) {
await db.dropCollection("itemCategories");
}
};
And here is the error I get when running it
ERROR: Could not migrate up 20210627041314-create-categories.js: Document failed validation BulkWriteError: Document failed validation
at OrderedBulkOperation.handleWriteError (C:\Users\username\projectDirectory\node_modules\mongodb\lib\bulk\common.js:1352:9)
at resultHandler (C:\Users\username\projectDirectory\node_modules\mongodb\lib\bulk\common.js:579:23)
at handler (C:\Users\username\projectDirectory\node_modules\mongodb\lib\core\sdam\topology.js:943:24)
at C:\Users\username\projectDirectory\node_modules\mongodb\lib\cmap\connection_pool.js:350:13
at handleOperationResult (C:\Users\username\projectDirectory\node_modules\mongodb\lib\core\sdam\server.js:558:5)
at MessageStream.messageHandler (C:\Users\username\projectDirectory\node_modules\mongodb\lib\cmap\connection.js:281:5)
at MessageStream.emit (events.js:321:20)
at processIncomingData (C:\Users\username\projectDirectory\node_modules\mongodb\lib\cmap\message_stream.js:144:12)
at MessageStream._write (C:\Users\username\projectDirectory\node_modules\mongodb\lib\cmap\message_stream.js:42:5)
at doWrite (_stream_writable.js:441:12)
Assuming collection name user_demo and having 2 fields only ( _id, name )
Create collection Schema Validator
db.createCollection("user_demo", {
validator: {
$jsonSchema: {
bsonType: "object",
title: "User Object Validation",
required: [ "_id","name"],
properties: {
_id: {
bsonType: "binData",
description: "Unique identifier,I am using it instead of objectId for portibility",
pattern: "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
},
name: {
bsonType: "string",
description: "'name' must be a string and is required",
maxLength: 50,
minLength: 1
}
}
}
}
} )
Insert data in collection
a) If you already have a uuid4
db.user_demo.insertOne({_id: UUID("a5750db3-1616-45a4-bf92-6a44c3e67342"), name:"shiva"})
b) If you want random uuid4
db.user_demo.insertOne({_id: UUID(), name:"explore"})
Tested with mongo version 6.0.3

node.js odata-server mongodb unable to post related entity

I have been working on a node.js odata server based on this example: How to set up a nodejs OData endpoint with odata-server
I have everything working... I can read, update, insert, delete. But I am trying to associate a Journal with a Tasks and I am having problems.
I have tried several different ways outlined here: Operations (OData Version 2.0)
Here is my code:
/* global $data */
require('odata-server');
$data.Class.define("Task", $data.Entity, null, {
Id: { type: "id", key: true, computed: true, nullable: false },
Title: { type: "string", required: true, maxLength: 200 },
Journals: { type: "array", elementType: "Journal"
, inverseProperty: "Task" }
});
$data.Class.define("Journal", $data.Entity, null, {
Id: { type: "id", key: true, computed: true, nullable: false },
Entry: { type: "string" },
DateInserted: { type: "string" },
Task: { type: "object", elementType: "Task" , inverseProperty: "Journals" }
});
$data.EntityContext.extend("obb", {
Tasks: { type: $data.EntitySet, elementType: Task },
Journals: { type: $data.EntitySet, elementType: Journal }
});
$data.createODataServer(obb, '/api-v0.1', 2046, 'localhost');
Question:
Is this feature even available from odata-server what would the post look like to link a Journal to a Task?
I am using fiddler2 and composing a POST I have tried these urls:
//localhost:2046/api-v0.1/Tasks('the-id-of-a-task')/Journals
//localhost:2046/api-v0.1/Tasks('the-id-of-a-task')/Journals/$link
post body's I have tried:
{"Entry":"This is a test"}
{"url":"http://localhost:2046/api-v0.1/Journals('id-of-a-journal-in-the-db')"}
I have even tried to build out and post a Task with journals together and that didn't work.
Any help would be greatly appreciated. Thanks.

Sails 0.10 & Many-to-Many association - Get all associated data, not the first only

I have 2 models with a Many-to-Many association. My code to associate these two models is working well (it create a new collection item_languages__language_items with the corresponding documents inside). But then I have trouble to get all the associated data (languages) of a specific item. I'm using MongoDB.
// Item.js
module.exports = {
schema: true,
autoPK: false,
attributes: {
uuid: {
type: 'string',
primaryKey: true,
unique: true,
required: true,
uuidv4: true
},
languages: {
collection: 'language',
via: 'items',
dominant: true
}
}
}
// Language.js
module.exports = {
schema: true,
autoPK: false,
attributes: {
code: {
type: 'string',
primaryKey: true,
required: true,
minLength: 2,
maxLength: 2,
unique: true
},
items: {
collection: 'item',
via: 'languages'
}
}
}
Data stored in the item_languages__language_items collection:
/* 0 */
{
"language_items" : "es",
"item_languages" : "69e4f3a3-1247-4a06-ae2d-9df27ac9495b",
"_id" : ObjectId("5330bcebf8e0b61509c771d5")
}
/* 1 */
{
"language_items" : "fr",
"item_languages" : "69e4f3a3-1247-4a06-ae2d-9df27ac9495b",
"_id" : ObjectId("5330bd26f8e0b61509c771d6")
}
/* 2 */
{
"language_items" : "en",
"item_languages" : "69e4f3a3-1247-4a06-ae2d-9df27ac9495b",
"_id" : ObjectId("5330bedcc076355b09da3ccd")
}
Now in my ItemController.js, I want to get a specific item with all associated languages:
Item
.findOne({uuid: '69e4f3a3-1247-4a06-ae2d-9df27ac9495b'})
.populate('languages')
.exec(function (e, r) {
console.log(r.toJSON());
});
But here I get my item with only 1 associated language, when I expected to get the 3 associated languages.
This appears to be a bug in the current beta implementation of sails-mongo which keeps populate from working properly with custom-defined keys. Please post this to the sails-mongo issues forum! In the meantime the only solution appears to be to use the default MongoDB primary keys.

Mongo/Mongoose Invalid atomic update value error

I am trying to write to write an update to a Mongo document using the Mongoose findOneAndUpdate function. Essentially, I have a document that has an array of another Schema in it, and when I attempt to append more of those schema type, I get the following error:
[Error: Invalid atomic update value for $__. Expected an object, received object]
I'm having a hard time figuring out what this error even means, much less what its source is.
The data I'm attempting to update is as follows:
{ section_id: 51e427ac550dabbb0900000d,
version_id: 7,
last_editor_id: 51ca0c4b5b0669307000000e,
changelog: 'Added modules via merge function.',
committed: true,
_id: 51e45c559b85903d0f00000a,
__v: 0,
modules:
[ { orderId: 0,
type: 'test',
tags: [],
data: [],
images: [],
content: ["Some Content Here"] },
{ orderId: 1,
type: 'test',
tags: [],
data: [],
images: [],
content: ["Some Content Here"] },
{ orderId: 2,
type: 'test',
tags: [],
data: [],
images: [],
content: ["Some Content Here"] },
{ orderId: 3,
type: 'test',
tags: [],
data: [],
images: [],
content: ["Some Content Here"] },
{ orderId: 4,
type: 'test',
tags: [],
data: [],
images: [],
content: ["Some Content Here"] },
{ orderId: 5,
type: 'test',
tags: [],
data: [],
images: [],
content: ["Some Content Here"] } ] }
The only difference is that when I retrieve it, there are three fewer modules, and I append some new ones to the array.
Would love to hear any thoughts, at least as to what the error means!
This is probably because the updated object is still a Mongoose object.
Try to convert it to a JS object before the findOneAndUpdate
object = object.toString()
And delete any potential ID attribute
delete object._id
Or simply
object = object.toObject();
I had the same problem and it turned out I was using $push incorrectly. I was doing
{$push:thing_to_push}
But it needed to be
{$push:{list_to_push_into:thing_to_push}}
#Magrelo and #plus led me to an answer that worked. Something like:
MyModel.findOneAndUpdate({ section_id: '51e427ac550dabbb0900000d' }, mongooseObject.toObject(), { upsert: true }, function(err, results) {
//...
});
Try passing update parameter value as string instead of mongoose model object. I was getting same error when I use to pass model object. Below is the code difference.
Code that was having issue:
updateUser: function(req, res) {
**var updatedUserModel = new Users(req.body);**
Users.findOneAndUpdate({tpx_id:req.params.id}, {$set:**updatedUserModel**}, function(err, User){
...
}
}
Working code:
updateUser: function(req, res) {
Users.findOneAndUpdate({tpx_id:req.params.id}, {$set:**req.body**}, function(err, User) {
...
}
I had the same issue. I ended up by using finOne() method
create a new one if no found, update the existing one if found.
I know there are two operations. but I just haven't find any way to do it in one step.
Another thing to check is if you are sending passing an array of changes to $set. The error message that I received when calling something like this:
db.products.update( { sku: "abc123" },
{ $set: [
{quantity: 500},
{instock: true}
]
}
)
Gave me the [Error: Invalid atomic update value for $set. Expected an object, received object]
Changing it to an object worked.
db.products.update( { sku: "abc123" },
{ $set: {
quantity: 500,
instock: true
}
}
)

Resources