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/
Related
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'
});
So I have found quite few related posts on SO on how to update a field in a sub array, such as this one here
What I want to achieve is basically the same thing, but updating a field in a subarray dynamically, instead of just calling the field name in the query.
Now I also found how to do that straight in the main object, but cant seem to do it in the sub array.
Code to insert dynamically in sub-object:
_.each(data.data, function(val, key) {
var obj = {};
obj['general.'+key] = val;
insert = 0 || (Documents.update(
{ _id: data._id },
{ $set: obj}
));
});
Here is the tree of what I am trying to do:
Documents: {
_id: '123123'
...
smallRoom:
[
_id: '456456'
name: 'name1'
description: 'description1'
],
[
...
]
}
Here is my code:
// insert a new object in smallRoom, with only the _id so far
var newID = new Mongo.ObjectID;
var createId = {_id: newID._str};
Documents.update({_id: data._id},{$push:{smallRooms: createId}})
And the part to insert the other fields:
_.each(data.data, function(val, key) {
var obj = {};
obj['simpleRoom.$'+key] = val;
console.log(Documents.update(
{
_id: data._id, <<== the document id that I want to update
smallRoom: {
$elemMatch:{
_id : newID._str, <<== the smallRoom id that I want to update
}
}
},
{
$set: obj
}
));
});
Ok, having said that, I understand I can insert the whole object straight away, not having to push every single field.
But I guess this question is more like, how does it work if smallRoom had 50 fields, and I want to update 3 random fields ? (So I would NEED to use the _each loop as I wouldnt know in advance which field to update, and would not want to replace the whole object)
I'm not sure I 100% understand your question, but I think the answer to what you are asking is to use the $ symbol.
Example:
Documents.update(
{
_id: data._id, smallRoom._id: newID._str
},
{
$set: { smallroom.$.name: 'new name' }
}
);
You are finding the document that matches the _id: data._id, then finding the object in the array smallRoom that has an _id equal to newId._str. Then you are using the $ sign to tell Mongo to update that object's name key.
Hope that helps
Let' say I have a company collection:
[{
name: 'x',
code: 'a',
},
{
name: 'y',
code: 'b',
}]
I want to find the company with code 'a' and insert this to another collection called projects. I wrote something like this:
var collectionP = db.collection('projects');
var collectionC = db.collection('company');
var foundCompany = collectionC.find({code: 'a'});
db.collectionP.insert(name: 'project1', company: foundCompany);
This doesn't work. Any idea?
Calling find returns a cursor, not a result set.
Your alternatives are either iterate over the cursor, if expecting multiple results:
var foundCompany = collectionC.find({code: 'a'});
foundCompany.forEach(function(fc) {
db.collectionP.insert(name: 'project1', company: fc);
}
or convert it into an array if you want all results in one document:
var foundCompany = collectionC.find({code: 'a'}).toArray();
db.collectionP.insert(name: 'project1', company: foundCompany);
or if you only expect to match a single company, use findOne or its equivalent in your language:
var foundCompany = collectionC.findOne({code: 'a'});
db.collectionP.insert(name: 'project1', company: foundCompany);
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);
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);