How to append a key:value to a MongoDB cursor? - mongodb

Is it possible to append a key:value to a MongoDB cursor?
I tried this:
cursor = collection.find(query,projection)
cursor['my_message'] = "value here" # trying to add key:value here
But it doesn't seem to work (500).
In more context, this works:
dbname = 'my_db'
db = connection[dbname]
collection = db.my_collection
query = {'key_1': my_var}
projection = {'key_2':1}
cursor = collection.find(query,projection)
response.content_type = 'application/json'
return dumps(cursor)
This doesn't:
dbname = 'my_db'
db = connection[dbname]
collection = db.my_collection
query = {'key_1': my_var}
projection = {'key_2':1}
cursor = collection.find(query,projection)
cursor['my_message'] = "value here" # trying to add key:value here
response.content_type = 'application/json'
return dumps(cursor)
Edit: And just to visualise what is being returned successfully (without the appended value), it is something like:
[{ document_1 },{ document_2 },{ document_3 }]
And I expect it to look something like:
["my_message":"value here",{ document_1 },{ document_2 },{ document_3 }]
Edit: I tried the following as an alternative and also got a 500.
entries = []
cursor = collection.find(query,projection)
for entry in cursor:
entries.append(entry)
entries['my_message'] = "value here"
response.content_type = 'application/json'
return dumps(entries)

Really, WiredPrarie answered this for you right at the beginning, and everyone is saying the same thing.
We know what you want to do. You want your serialized response to be sent back with some information you want to put in and then the resultset. I also presume that you want to use these results and your other data, likely loaded into some JavaScript processing store.
I have never seen anything that didn't expect some sort of structure like:
{
"result": "ok",
"meta": [{ akey: "avalue"}, {bkey: "bvalue"}],
"results:[ // this is your 'entries' value here
{ document_1 },
{ document_2 },
{ document_3 },
....
So what everyone is saying is embed your entries into another structure that you are going to serialize and return. By trying to push your other keys into the entries list you are doing it the wrong way around.

Related

how can I set the value of objectId to another property different that _id when creating a document?

I'm trying to create an object that looks like this:
const userSettingsSchema = extendSchema(HistorySchema, {
user: //ObjectId here,
key:{type: String},
value:{type: String}
});
this is the post method declared in the router
app.post(
"/api/user/settings/:key",
userSettingsController.create
);
and this is the method "create":
async create(request, response) {
try {
const param = request.params.key;
const body = request.body;
console.log('body', body)
switch (param) {
case 'theme':
var userSettings = await UserSettings.create(body) // user:objecId -> missing...
response.status(201).send(userSettings);
break;
}
} catch (e) {
return response.status(400).send({ msg: e.message });
}
}
I don't know how to assign the value of ObjectId to the user property, because ObjectId is generate when the doc is created, thus, I can not do this: userSettings.user = userSettings._id, because the objectr is already. I only manage to get something like this created:
{
"_id": "60c77565f1ac494e445cccfe",
"key": "theme",
"value": "dark",
}
But it should be:
{
"user": "60c77565f1ac494e445cccfe",
"key": "theme",
"value": "dark",
}
_id is the only mandatory property of a document. It is unique identifier of the document and you cannot remove it.
If you provide document without _id the driver will generate one.
You can generate ObjectId as
let id = mongoose.Types.ObjectId();
and assign it to as many properties as you want.
You can even generate multiple different ObjectIds for different properties of the same document.
Now, you don't really need to assign ObjectId to "user" property. _id will do just fine. In fact it is most likely you don't need user's settings in separate collection and especially as multiple documents with single key-value pair.
You should be good by embedding "settings" property to your "user" collection as a key-value json.

How to target a field in Prisma and get a flat array of values rather than an array of objects

I just started using Primsa 2 so I am still a noob at this but all I am trying to do is create a flat array of strings(Array<number>) based on the values I get from a specific field. Right now when I target that field it gives me an array of objects like this: userIds: [{ issueId: 1, userId: 1 }]
All I want is the value I get from the userId key and the array to return like this userIds: [ 1 ]. I was able to fix this with some formatting code after the query which was done like so:
const issues = project.issues.map(issue => ({ ...issue, userIds: [...issue.userIds.map((id) => id.userId)] }))
const _project = { ...project, issues }
However, this doesn't seem like the most optimal solution. If this is the only way that is fine but I assume with the power that Prisma has for querying, this is something I can do just in the query alone?
For reference, my query currently looks like this:
const project = await prisma.project.findFirst({
where: { id: req.currentUser.projectId },
include: { users: true, issues: { include: { userIds: true } } },
})
Thanks in advance!
Can you show your schema? Perhaps you can model the relation differently. However, unless if you provide a field, userIds, that is a flat array and not a field of a an other relation it will be returned as a list of objects as you have already.

mongo forEach unable to update array in document

I'm trying write a mongo script to run in RoboMongo that will loop through all documents in a collection. Each document contains an array myArray. The documents look like this:
{
"name": "myApp",
"myArray": [
{ "env": "dev", "dbHost": "db2dev.local" },
{ "env": "prod", "dbHost": "db1prod.local" }
]
I want to copy the dbHost field that is defined in dev to prod. So the above result would be:
{
"name": "myApp",
"myArray": [
{ "env": "dev", "dbHost": "db2dev.local" },
{ "env": "prod", "dbHost": "db2dev.local" }
]
When I try to access the field myArray[0] I get a syntax error that says:
TypeError: myDoc.myArray[0] is undefined
The function is something like this:
db.myCollection.find().forEach( function(myDoc) {
var devIdx = 0;
var prodIdx = 1;
if (myDoc.myArray[0].env !== 'dev')}
devIdx = 1;
prodIdx = 0;
}
myDoc.myArray[prodIdx].dbHost = myDoc.myArray[devIdx].dbHost;
print(myDoc);
});
I've examined the collection (it is very small) and each document has a myArray field as it should with exactly two values (one for dev and one for prod) in the array.
What am I doing wrong? What is the correct syntax to use inside a mongo script? Is updating arrays in a document not supported?
Searching for solution
I've searched and found forEach examples but most are trivial and none include an array being accessed or changed.
The mongo docs are also very simplistic: https://docs.mongodb.com/v3.6/reference/method/cursor.forEach/
Mongo javascript does not allow you to access arrays directly like you are trying to do (unless you are in a for loop). So a solution is shown below:
db.myCollection.find({}).forEach( function(myDoc) {
var foundDevEntry = null;
var updatedProdEntry = false;
// First time loop to get a copy of the dev entry
for (var idx in myDoc.myArray) {
if (myDoc.myArray[idx].env === 'dev') {
foundDevEntry = myDoc.myArray[idx];
}
}
// 2nd time loop to update the value
for (var idx in myDoc.myArray) {
if (myDoc.myArray[idx].env === 'prod') {
myDoc.myArray[idx].dbHost = foundDevEntry.dbHost;
}
}
// Now update the database with this change
db.myCollection.update({_id: myDoc._id}, {$set: {"myArray": myDoc.myArray}});
print(myDoc); // So results are also returned when query is run
});
I've stripped out error checking to focus on the change required. What (to me) is odd is that the syntax myDoc.myArray[idx] is actually valid but only inside a loop!
The following references helped me come to a solution:
Update in forEach on mongodb shell
https://www.mysoftkey.com/mongodb/how-to-use-foreach-loop-in-mongodb-to-manipulate-document/
I should add that some solutions I read said that to update an array you had to re-build the array (https://stackoverflow.com/a/22657219/3281336). I did not do that in my solution and it did work but wanted to share it.

Update nested array object (put request)

I have an array inside a document of a collection called pown.
{
_id: 123..,
name: pupies,
pups:[ {name: pup1, location: somewhere}, {name: pup2, ...}]
}
Now a user using my rest-service sends the entire first entry as put request:
{name: pup1, location: inTown}
After that I want to update this element in my database.
Therefore I tried this:
var updatedPup = req.body;
var searchQuery = {
_id : 123...,
pups : { name : req.body.name }
}
var updateQuery = {
$set: {'pups': updatedPup }
}
db.pown.update(searchQuery, updateQuery, function(err, data){ ... }
Unfortunately it is not updating anythig.
Does anyone know how to update an entire array-element?
As Neil pointed, you need to be acquainted with the dot notation(used to select the fields) and the positional operator $ (used to select a particular element in an array i.e the element matched in the original search query). If you want to replace the whole element in the array
var updateQuery= {
"$set":{"pups.$": updatedPup}
}
If you only need to change the location,
var updateQuery= {
"$set":{"pups.$.location": updatedPup.location}
}
The problem here is that the selection in your query actually wants to update an embedded array element in your document. The first thing is that you want to use "dot notation" instead, and then you also want the positional $ modifier to select the correct element:
db.pown.update(
{ "pups.name": req.body.name },
{ "$set": { "pups.$.locatation": req.body.location }
)
That would be the nice way to do things. Mostly because you really only want to modify the "location" property of the sub-document. So that is how you express that.

Nested document insert into MongoDB with C#

I am trying to insert nested documents in to a MongoDB using C#. I have a collection called categories. In that collection there must exist documents with 2 array, one named categories and one named standards. Inside those arrays must exist new documents with their own ID's that also contain arrays of the same names listed above. Below is what I have so far but I am unsure how to proceed. If you look at the code what I want to do is add the "namingConventions" document nested under the categories array in the categories document however namingConventions must have a unique ID also.
At this point I am not sure I have done any of this the best way possible so I am open to any and all advice on this entire thing.
namespace ClassLibrary1
{
using MongoDB.Bson;
using MongoDB.Driver;
public class Class1
{
public void test()
{
string connectionString = "mongodb://localhost";
MongoServer server = MongoServer.Create(connectionString);
MongoDatabase standards = server.GetDatabase("Standards");
MongoCollection<BsonDocument> categories = standards.GetCollection<BsonDocument>("catagories");
BsonDocument[] batch = {
new BsonDocument { { "categories", new BsonArray {} },
{ "standards", new BsonArray { } } },
new BsonDocument { { "catagories", new BsonArray { } },
{ "standards", new BsonArray { } } },
};
categories.InsertBatch(batch);
((BsonArray)batch[0]["categories"]).Add(batch[1]);
categories.Save(batch[0]);
}
}
}
For clarity this is what I need:
What I am doing is building a coding standards site. The company wants all the standards stored in MongoDB in a tree. Everything must have a unique ID so that on top of being queried as a tree it can be queried by itself also. An example could be:
/* 0 */
{
"_id" : ObjectId("4fb39795b74861183c713807"),
"catagories" : [],
"standards" : []
}
/* 1 */
{
"_id" : ObjectId("4fb39795b74861183c713806"),
"categories" : [{
"_id" : ObjectId("4fb39795b74861183c713807"),
"catagories" : [],
"standards" : []
}],
"standards" : []
}
Now I have written code to make this happen but the issue seems to be that when I add object "0" to the categories array in object "1" it is not making a reference but instead copying it. This will not due because if changes are made they will be made to the original object "0" so they will not be pushed to the copy being made in the categories array, at least that is what is happening to me. I hope this clears up what I am looking for.
So, based on your latest comment, it seems as though this is the actual structure you are looking for:
{
_id: ObjectId(),
name: "NamingConventions",
categories: [
{
id: ObjectId(),
name: "Namespaces",
standards: [
{
id: ObjectId(),
name: "TitleCased",
description: "Namespaces must be Title Cased."
},
{
id: ObjectId().
name: "NoAbbreviations",
description: "Namespaces must not use abbreviations."
}
]
},
{
id: ObjectId(),
name: "Variables",
standards: [
{
id: ObjectId(),
name: "CamelCased",
description: "variables must be camel cased."
}
]
}
]
}
Assuming this is correct, then the below is how you would insert one of these:
var collection = db.GetCollection("some collection name");
var root = new BsonDocument();
root.Add("name", "NamingConventions");
var rootCategories = new BsonArray();
rootCategories.Add(new BsonDocument
{
{ "id": ObjectId.GenerateNewId() },
{ "name", "Namespaces" },
{ "standards", new BsonArray() }
});
root.Add("categories", rootCategories);
//etc...
collection.Save(root);
Hope that helps, if not, I give up :).
So, I guess I'm confused by what you are asking. If you just want to store the namingConventions documents inside the array, you don't need a collection for them. Instead, just add them to the bson array and store them.
var categoriesCollection = db.GetCollection<BsonDocument>("categories");
var category = new BsonDocument();
var namingConventions = new BsonArray();
namingConventions.Add(new BsonDocument("convention1", "value"));
category.Add("naming_conventions", namingConventions);
categoriesCollection.Insert(category);
This will create a new document for a category, create an array in it called naming_conventions with a single document in it with an element called "convention1" and a value of "value".
I also am not quite sure what you are trying to accomplish. Perhaps if you posted some sample documents in JSON format we could show you the C# code to write documents that match that.
Alternatively, if you wish to discuss your schema, that could also be better done in the context of JSON rather than C#, and once a schema has been settled on then we can discuss how to write documents to that schema in C#.
One thing that didn't sound right in your original description was the statement "in that collection must exist 2 arrays". A collection can only contain documents, not arrays. The documents themselves can contain arrays if you want.
var filter = Builders<CollectionDefination>.Filter.Where(r => r._id== id);
var data = Builders<CollectionDefination>.Update.Push(f=>
f.categories,categoriesObject);
await _dbService.collection.UpdateOneAsync( filter,data);
Note: Make sure embedded document type [Categories] is array.