how to update one table with the _id from another table in Mongodb - mongodb

I exported data from a MySQL database into JSON and imported it into MongoDB. The problem:
When I imported clients, MongoDB created its own _id field (I know this is built in functionality, but MySQL used a clientID, autoincrementing integer).
SO, when I imported my appointments collection, the clientID was renamed oldClientID. I'd like the clientID field to be the ObjectID of the corresponding client.
My schemas:
const apptSchema = new mongoose.Schema({
ID: Number,
clientID: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Client'
},
oldClientID: Number,
...other field data
});
const clientSchema = new mongoose.Schema({
ID: Number,
familyID: Number,
first: String,
last: String,
});
Sample Patient Data:
{
"_id" : ObjectId("5d82240f7c8ddd03b62aee6a"),
"ID" : 18,
"familyID" : 6,
"first" : "Jane",
"last" : "Doe"
}
Sample Appointment Data
{
"_id" : ObjectId("5d82c8b95627367d122087f9"),
"ID" : 1885,
"oldPatientID" : 18,
"scheduled" : ISODate("2015-08-05T11:20:00Z"),
"note" : ""
},
{
"_id" : ObjectId("5d82c8b95627367d122088a8"),
"ID" : 2066,
"oldPatientID" : 18,
"scheduled" : ISODate("2015-09-17T16:00:00Z"),
"note" : ""
}
What appointments should look like:
{
"_id" : ObjectId("5d82c8b95627367d122087f9"),
"ID" : 1885,
"clientID": ObjectId("5d82240f7c8ddd03b62aee6a"),
"oldPatientID" : 18,
"scheduled" : ISODate("2015-08-05T11:20:00Z"),
"note" : ""
},
{
"_id" : ObjectId("5d82c8b95627367d122088a8"),
"ID" : 2066,
"clientID" : ObjectId("5d82240f7c8ddd03b62aee6a"),
"oldPatientID" : 18,
"scheduled" : ISODate("2015-09-17T16:00:00Z"),
"note" : ""
}
I am open to learning how to achieve this in the mongo shell or using mongoose in express (or if there is another cool way, like in Robo3T).

MongoDB will always use _id as the primary key, this behavior cannot be overwritten, though you can use the _id with values from your custom id. Though this might be confusing, it is better to use indexing on your custom id, and you don't need to use ObjectId for the custom index field, but can use your own custom id schema, like UUID or an incrementing integer value etc. though it has to be generated/incremented by you or some framework, like JPA
Check Indexes
For Mongoose, you can do;
new mongoose.Schema({
customId: { type: Number, index: true }
...other field data
});
with index: true

Ok, this worked out for me, although I'm sure there has to be an easier way:
db.getCollection("appts").aggregate(
[
{
"$lookup" : {
"from" : "clients",
"localField" : "clientID",
"foreignField" : "ID",
"as" : "CLIENT"
}
},
{
"$lookup" : {
"from" : "appttypes",
"localField" : "type",
"foreignField" : "ID",
"as" : "TYPE"
}
},
{
"$lookup" : {
"from" : "apptstatuses",
"localField" : "status",
"foreignField" : "ID",
"as" : "STATUS"
}
},
{
"$project" : {
"_id" : "$_id",
"clientID" : "$CLIENT._id",
"scheduled" : "$scheduled",
"note" : "$note",
}
},
{
"$out" : "apptslinked"
}
]
);
Then I exported that as JSON, dropped the appts table, and did a mongoimport using that file.

Related

MongoDb "left join" with different column types

I have two collections: User and UserProfile.
UserProfile references User by the property userId as UUID.
User collection have _id field but as string.
How can I "left join" these two collections to find out what documents don't have a match?
Here is what I got so far:
db.UserProfile.aggregate({
$lookup:
{
from: 'User',
localField: 'userId', // this is UUID
foreignField: '_id', // this is string
as: 'user'
}
})
Here are two sample entities:
User:
{
"_id" : "0c7e18b2-3682-444d-a62b-30e311e76891",
"userName" : "programad",
"normalizedUserName" : "PROGRAMAD",
"email" : "programad#gmail.com",
"normalizedEmail" : "PROGRAMAD#GMAIL.COM",
"emailConfirmed" : true,
"concurrencyStamp" : "56d3d071-0e30-458a-880a-ed75e20863a9",
"lockoutEnabled" : true,
"roles" : [ ],
"claims" : [ ],
"logins" : [ ],
"tokens" : [ ],
"recoveryCodes" : [ ]
}
UserProfile:
{
"_id" : UUID("a4d5b6d5-f181-4267-5b81-08d64d02d681"),
"userId" : UUID("0c7e18b2-3682-444d-a62b-30e311e76891"),
"createDate" : ISODate("2018-08-01T00:00:00.000-03:00"),
"type" : "Personal",
"name" : "Daniel Gomes",
"motto" : "Code Lover",
"bio" : "bio yadda yadda",
"studioName" : "My studio name",
"location" : "Santos/Brazil",
"externalLinks" : [ ]
}
Ok, a gentleman called Vignan Yarlagadda helped me on this.
I needed to find wich profiles lack users or vice-versa.
He came around with this:
db.UserMissing.drop();
var cur = db.UserProfile.find({"_id":{"$exists":1}}).addOption(16);
cur.forEach(function(x){
db.UserMissing.insert({"_id":x.userId,"userId":x.userId})
});
var cur = db.User.find({"_id":{"$exists":1}}).addOption(16);
cur.forEach(function(x){
var string=x._id;
var y=UUID(string);
db.UserProfile.find({"userId":y}).forEach(function(doc){
db.UserMissing.update({"userId":doc.userId},{"$set":{"Matching":true}},{"multi":true});
});
});
db.UserMissing.find({"Matching":{"$exists":0}});
It creates **a temporary collection** called UserMissing and I can see witch ones to focus my attention.

$addToSet is not updating the object in array?

I'm beginner in mongodb I want to add one object in Array tag. ie:Array of Objects..I'm using $addToSet Operator but it's not working.
I have a collection like this:
{
"_id" : ObjectId("5c231693d1b726c55ec914a3"),
"name" : "Christine Franklin",
"degrees" : [
{
"level" : "Master",
"major" : "Cs",
"completion_year" : "2018",
"faculty" : "AKz"
},
{
"level" : "Bachelor",
"major" : "Biology",
"completion_year" : 2008,
"faculty" : "Science"
}
],
"school_email" : "cfranklin#example.edu",
"email" : "christine#example.com"
}
This is my schema:
const schema=new mongoose.Schema({
name:String,
degrees:[String],
school_email:String,
email:String
});
const GradeDetails=mongoose.model('graduate',schema);
This is my code:
const result=await GradeDetails.update({"name" : "Christine Franklin"},{
$addToSet:{
"degrees":{
"level" : "PG",
"major" : "M.Tech",
"completion_year" : "2018",
"faculty" : "KG"
}}
});
console.log(result);
Thanks in advance... can anyone solve this problem?
Besides the problem with the badly matching types, did you check if you object was updated in the db and just not displayed correctly? If so, please add the flag { new : true } to your update query options. Otherwise, the old object will be returned.

Mongodb return objectId as string

db.getCollection('User').find({
"userId" : ObjectId("5a141ac4048378xb52c3e5a9"),
"userRole" : "ADMIN",
"Id" : "1234567890"})
result:
{
"userId" : ObjectId("5a141ac4048378xb52c3e5a9"),
"userRole" : "ADMIN",
"Id" : "1234567890"
}
Expecting output:
{
"userId" : "5a141ac4048378xb52c3e5a9",
"userRole" : "ADMIN",
"Id" : "1234567890"
}
I am very new to mongodb i nedded to return objectId as String ,i neeed some suggestion to do that.
It can be done simply using the below approach
db.User.find({"userId": objectId("5a141ac4048378ab52c3e5a9")}).map(
function(doc) {
return { "userId": doc.userId.str}
});
Please see ObjectId for more methods
You can try use a aggregation
But ObjectId isn't strings, it's just numbers, why you want present it as string?

MongoDB Conditional validation on arrays and embedded documents

I have a number of documents in my database where I am applying document validation. All of these documents may have embedded documents. I can apply simple validation along the lines of SQL non NULL checks (these are essentially enforcing the primary key constraints) but what I would like to do is apply some sort of conditional validation to the optional arrays and embedded documents. By example, lets say I have a document that looks like this:
{
"date": <<insertion date>>,
"name" : <<the portfolio name>>,
"assets" : << amount of money we have to trade with>>
}
Clearly I can put validation on this document to ensure that date name and assets all exist at insertion time. Lets say, however, that I'm managing a stock portfolio and the document can have future updates to show an array of stocks like this:
{
"date" : <<insertion date>>,
"name" : <<the portfolio name>>,
"assets" : << amount of money we have to trade with>>
"portfolio" : [
{ "stockName" : "IBM",
"pricePaid" : 155.39,
"sharesHeld" : 100
},
{ "stockName" : "Microsoft",
"pricePaid" : 57.22,
"sharesHeld" : 250
}
]
}
Is it possible to to apply a conditional validation to this array of sub documents? It's valid for the portfolio to not be there but if it is each document in the array must contain the three fields "stockName", "pricePaid" and "sharesHeld".
MongoShell
db.createCollection("collectionname",
{
validator: {
$or: [
{
"portfolio": {
$exists: false
}
},
{
$and: [
{
"portfolio": {
$exists: true
}
},
{
"portfolio.stockName": {
$type: "string",
$exists: true
}
},
{
"portfolio.pricePaid": {
$type: "double",
$exists: true
}
},
{
"portfolio.sharesHeld": {
$type: "double",
$exists: true
}
}
]
}
]
}
})
With this above validation in place you can insert documents with or without portfolio.
After executing the validator in shell, then you can insert data of following
db.collectionname.insert({
"_id" : ObjectId("58061aac8812662c9ae1b479"),
"date" : ISODate("2016-10-18T12:50:52.372Z"),
"name" : "B",
"assets" : 200
})
db.collectionname.insert({
"_id" : ObjectId("58061ab48812662c9ae1b47a"),
"date" : ISODate("2016-10-18T12:51:00.747Z"),
"name" : "A",
"assets" : 100,
"portfolio" : [
{
"stockName" : "Microsoft",
"pricePaid" : 57.22,
"sharesHeld" : 250
}
]
})
If we try to insert a document like this
db.collectionname.insert({
"date" : new Date(),
"name" : "A",
"assets" : 100,
"portfolio" : [
{ "stockName" : "IBM",
"sharesHeld" : 100
}
]
})
then we will get the below error message
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 121,
"errmsg" : "Document failed validation"
}
})
Using Mongoose
Yes it can be done, Based on your scenario you may need to initialize the parent and the child schema.
Shown below would be a sample of child(portfolio) schema in mongoose.
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var portfolioSchema = new Schema({
"stockName" : { type : String, required : true },
"pricePaid" : { type : Number, required : true },
"sharesHeld" : { type : Number, required : true },
}
References:
http://mongoosejs.com/docs/guide.html
http://mongoosejs.com/docs/subdocs.html
Can I require an attribute to be set in a mongodb collection? (not null)
Hope it Helps!

How to update particular array element in MongoDB

I am newbie in MongoDB. I have stored data inside mongoDB in below format
"_id" : ObjectId("51d5725c7be2c20819ac8a22"),
"chrom" : "chr22",
"pos" : 17060409,
"information" : [
{
"name" : "Category",
"value" : "3"
},
{
"name" : "INDEL",
"value" : "INDEL"
},
{
"name" : "DP",
"value" : "31"
},
{
"name" : "FORMAT",
"value" : "GT:PL:GQ"
},
{
"name" : "PV4",
"value" : "1,0.21,0.00096,1"
}
],
"sampleID" : "Job1373964150558382243283"
I want to update the value to 11 which has the name as Category.
I have tried below query:
db.VariantEntries.update({$and:[ { "pos" : 117199533} , { "sampleID" : "Job1373964150558382243283"},{"information.name":"Category"}]},{$set:{'information.value':'11'}})
but Mongo replies
can't append to array using string field name [value]
How one can form a query which will update the particular value?
You can use the $ positional operator to identify the first array element to match the query in the update like this:
db.VariantEntries.update({
"pos": 17060409,
"sampleID": "Job1373964150558382243283",
"information.name":"Category"
},{
$set:{'information.$.value':'11'}
})
In MongoDB you can't adress array values this way. So you should change your schema design to:
"information" : {
'category' : 3,
'INDEL' : INDEL
...
}
Then you can adress the single fields in your query:
db.VariantEntries.update(
{
{"pos" : 117199533} ,
{"sampleID" : "Job1373964150558382243283"},
{"information.category":3}
},
{
$set:{'information.category':'11'}
}
)