How to get the inserted document's ID in MongoDB - mongodb

I'm writing a script for the mongo shell to populate some data for test.
I have two collections: club, and team, and in the team's document, it has a objectId reference to the club.
What I did is as following:
db.club.drop();
var club_1_id;
db.club.insert({name:'Club 1',
venue:'Somewhere'},
function(err, doc){
club_1_id=doc._id;
});
db.team.drop();
var team_1_id;
db.team.insert({name:'Team 1', club:{id: club_1_id, name: 'Club 1'}},
function(err, doc){
team_1_id=doc._id;
});
I'm actually not so surprised to see that in the team document, the club's ID is inserted to be null, cause the call-back function may not be called in a timely fashion.
So in this case how can I set the id right?

You could try something like:
db.club.drop();
var club_1_id = new ObjectId();
db.club.insert({_id:club_1_id, name:'Club 1',venue:'Somewhere'});
db.team.drop();
var team_1_id = new ObjectId();
db.team.insert({_id:team_1_id, name:'Team 1', club:{id: club_1_id, name: 'Club 1'}});

var club_doc = {
_id: ObjectId()
name:'Club 1',
venue:'Somewhere'
}
var id = club_doc._id;
db.club.insert(club_doc);
var team_doc = {
_id: ObjectId(),
name:'Team 1',
club:{
id: id,
name: 'Club 1'
}
}
var teamID = team_doc._id;
db.team.insert(team_doc);

Related

BelongsTo in Sails.js

Hello, I need your help please with 2 questions.
I have 2 Models
One to Many
(One) Customer{ id, names, dni} -> Invoice {id, date, ....customer_id} (Many)
1. How can I get this?
I need to consume the api "GET /api/invoices" and that the json return of this, in turn, returns an array
[{
id: 1,
date: '2022-01-01',
....invoice
customer: {
dni: 1,
names: 'Example'
}
},
{
id: 2,
date: '2022-01-02',
....invoice
customer: {
dni: 2,
names: 'Example 2'
}
},
]
So far what I have found in the sailsjs documentation are only examples with POPULATE, where they only show how to list the User model with its corresponding created ones (hasMany)
//var users = await User.find().populate('pets');
// The users object would look something like the following
// [{
// id: 123,
// firstName: 'Foo',
// lastName: 'Bar',
// pets: [{
// id: 1,
// breed: 'labrador',
// type: 'dog',
// name: 'fido',
// user: 123
// }]
// }]
//---This is not what I need.
Is there a function or configuration that I have not found?
Or would I do something like this?
Invoices.find().exec(async(err, invoices)=>{
if(invoices){
for(i = 0; i< invoices.length; i++){
const customer = await Customer.find({id: invoices[i].customer_id});
invoices[i].customer = customer;
}
});
The point is that this takes much longer than doing a query with join
const invoices = await sails.sendNativeQuery('SELECT * from INVOICE A A inner join CUSTOMER B on A.customer_id=B.id ', []);
But I don't know how to get a JSON with the previous structure if I do it by query
2. What is the best option that can solve my problem?
The populate method works in both directions: oneToMany, manyToMany, and manyToOne:
https://sailsjs.com/documentation/reference/waterline-orm/queries/populate
If any condition is required, you could check the details on the section Populating a collection association:
var usersNamedFinn = await User.find({ name:'Finn' })
.populate('currentSwords', {
where: {
color: 'purple'
},
limit: 3,
sort: 'hipness DESC'
});

How to delete in cascade in several models with mongoose?

I have these 3 models in mongoose:
TravelSchema
var travelSchema = new mongoose.Schema({
name: String,
description: String,
mexican_currency_value: mongoose.Schema.Types.Decimal128
})
travelSchema.pre('deleteOne', function(next) {
const id = this.getQuery()['_id'];
Product.deleteMany({ travel: id }, (err, value) => {
});
next();
});
ProductSchema
var productSchema = new mongoose.Schema({
name: String,
description: String,
purchased_amount: Number,
unit_price_mex: mongoose.Schema.Types.Decimal128,
unit_price_to_sell: mongoose.Schema.Types.Decimal128,
travel: { type: mongoose.Schema.Types.ObjectId, ref: 'Travel' }
})
InvoiceSchema
var invoiceSchema = new mongoose.Schema({
product: productSchema,
client: { type: mongoose.Schema.Types.ObjectId, ref: 'Client' },
purchased_amount: Number,
fch: String
});
Where Travel and Product have a one-to-many relationship and Product and Invoice have a one-to-many relationship.
I need the following:
When a Travel is deleted, all Products that are related to that Travel are also deleted.
When these Products are eliminated, all the Invoices related to each Product are also eliminated.
I have managed to eliminate all the products, but when I try to eliminate the invoices I do not obtain the ids of the Products.
invoiceSchema.pre('deleteMany', (next) => {
console.log(this);
// this print { n: 2, ok: 1, deletedCount: 2 }
})
I think you should start the other way when looking at deleting all the related docs. Like you have travel id, with it get all the products and store their id in array and then your first delete should be of the invoices where product._id: { $ in: _arrayOfProducIds }. Once that is complete then deleteMany your products since you already have their ids in the _arrayOfProducIds and lastly deal with the Travel:
travelSchema.pre('deleteOne', function(next) {
const id = this.getQuery()['_id']; // travel id check
// Query to get all the product ids based on the travel id and return array for `$in`
const productIds = this.DoYourQuery // [productIds] check
Invoice.deleteMany({'product._id': { $in: productIds }}, // ... etc
Product.deleteMany({ _id': { $in: productIds }}, // ... etc
next();
});
I would assume you do not have a large number of products and invoices ... like thousands since then $in might be somewhat of a performance issue. Hope this helps.

Embedding fields in all mongodb documents

I have a collection with documents that follows this structure:
child:
{
id: int
name: string
age: int
dob: date
school: string
class: string
}
I would like to embed certain fields, into something like this:
child:
{
id : int
personalInfo {
name: string
age: int
dob: date
}
educationInfo {
school: string
class: string
}
}
How would one go across in doing this in code? I am new to Mongodb, so I apologize if my syntax is incorrect. All of the fields have one-to-one relationships with the child (i.e. one child has one id, one name, one age, one school etc.), so I'm also wondering if embedding is even necessary.
Please try to use $set to set the new field personalInfo and educationInfo, with #unset to remove old fields age, name etc. Before do it, it would be better to check all those fields exists through $exists, here are sample codes as below,
> var personfields = [ "name", "age", "dob" ];
> var educationFields = [ "school", "class" ];
> var query = {};
> personFields.forEach(function(k){ query[k] = {$exists: 1}});
> educationFields.forEach(function(k){ query[k] = {$exists: 1}});
> db.collection.find(query).forEach(function(doc){
var personalInfo = {};
var educationInfo = {};
for (var k in doc) {
if (personFields.indexOf(k) !== -1){
personalInfo[k] = doc[k];
} else if (educationFields.indexOf(k) !== -1) {
educationInfo[k] = doc[k];
}
}
db.collection.update({_id: doc._id},
{$set: {
personalInfo: personalInfo,
educationInfo: educationInfo},
$unset: {'name': '',
'age': '',
'dob': '',
'school': '',
'class': ''}});
})
It's OK to embed them, that's what document dB's are for. So if you need a migration, you'll basically use mongodb's functions like update ,with $set and $unset.
See more here: https://docs.mongodb.org/manual/reference/method/db.collection.update/

Adding to an array of lists in mongodb?

Silly question here, but I'm having trouble finding an example on the web.
I have set up a model on mongoDB that has arrays of objects, like so:
var ProjectSchema = new Schema({
project_id: { type: String },
item: {
title: { type: String },
owners: [{
first_name : {type: String} ,
middle_name : {type: String},
other_name: {type: String},
last_name: {type: String},
order: {type: Number, 'default': 1}
}]
}
}]
So you can see that item is a list of fields. And then owners is an array of lists of fields. When I create the project, I'm trying to set the owner like this:
var newProject = new Models.Project({
'item.title': title,
'item.owners[0].last_name': name,
'item.owners[0].order': 1
});
This doesn't generate an error, but the item fields don't get saved either (item.title saves fine).
I tried this too, but it gives me an error:
var newProject = new Models.Project({
'item.title': title,
item.owners.push({last_name: name, order: 1})
});
How am I supposed to refer to these sub-docs so I can save them?
Don't use dot notation in the fields of a new document, create it using the actual structure of the doc instead:
var newProject = new Models.Project({
item: {
title: title,
owners: [{
last_name: name,
order: 1
}]
});
it is a simple JSON object. With Javascript, it is quite straight forward. Below code generates the sample object given in the mongoDB doc:
var address1 = new Object();
address1.street = "123 Fake Street";
address1.city = "Faketon";
address1.state = "MA";
address1.zip = "12345";
var address2 = new Object();
address2.street = "1 Some other Street";
address2.city = "Boston";
address2.state = "MA";
address2.zip = "12345";
var data = new Object();
data._id = "joe";
data.name = "Joe Bookreader";
var addressArray = new Array();
addressArray.push(address1);
addressArray.push(address2);
data.addresses = addressArray;
alert(JSON.stringify(data));

How to get last inserted id using the JS api?

Using the javascript api for MongoDB, how do you get the ID of the last inserted object? i.e.
obj = {a: 1, b: 2};
db.foo.insert(obj);
How do I get the ID for obj?
The people on #mongodb were helpful. The JS API doesn't currently support this, but you can use your own id. To generate a "normal" id, do _id: new ObjectId(). So the example in my question would be:
id = new ObjectId();
obj = {a: 1, b: 2, _id: id};
db.foo.insert(obj);
If you run
db.collection("venues").insert( {name: "test3", FSid: "test3"}, function( err, ret) {
console.log( ret )
})
it returns
{ result: { ok: 1, n: 1 },
ops: [ { name: 'test3', FSid: 'test3', _id: 57cb0a1162cecfe636df6fc1 } ],
insertedCount: 1,
insertedIds: [ 57cb0a1162cecfe636df6fc1 ] }
So you can get your ids along with all inserted objects through:
ret.ops[0]._id
or straight
ret.insertedIds[0]
Now,the mongo native js api supports this. You can get the last id like this:
collection.insert(line, {w : 1}, function(err, inserted) {
inserted[0]._id
}
insert sets the _id property on the inserted object, but it looks like you have to wait for the object to return. The best documentation I've found for this is (unfortunately) in the source code:
https://github.com/mongodb/node-mongodb-native/blob/master/lib/mongodb/collection.js
If you insert the data like this:
var temptodo = new User({
title: data.todo.text,
email: socket.handshake.email,
created_at: Date.now(),
completed: false,
sid: socket.handshake.sid
});
temptodo.save( function(error, User){
console.log("this is the id for the new todo. "+User._id);
console.log('Todo saved in database with sid: '+socket.handshake.sid);
});
Then you can grab the _id like this: console.log("this is the id for the new todo. "+User._id);