inserting a new document in the arrray of documents - mongodb

I want to add a new document to the following document having an outer key "User"
{
name:himani,
User:[
{
_id:e25ffgf627627,
Name:User1
},
{
_id:fri2i2jhjh9098,
Name:User2
}
]
};
Below is my code in which I am trying to add a new document to already existing document.
My code is:
var server = MongoServer.Create("mongodb://username:password#localhost:27017/?safe=true");
SafeMode mode = new SafeMode(true);
SafeModeResult result = new SafeModeResult();
var db = server.GetDatabase("himani");
var coll = db.GetCollection("test");
BsonDocument document = new BsonDocument();
document.Add("name", "himani");
result = coll.Insert(document, mode);
BsonDocument nested = new BsonDocument();
nested.Add("1", "heena").Add("2", "divya");
BsonArray a = new BsonArray();
a.Add(2);
a.Add(5);
nested.Add("values", a);
document["3"] = new BsonArray().Add(BsonValue.Create(nested));
coll.Save(document);
var query = Query.And(
Query.EQ("name", "himani"),
Query.EQ("3.1", "heena")
);
var match = coll.FindOne(query);
var update = Update.AddToSet("3", new BsonDocument {{ "count", "2" }});
coll.Update(query, update);
I want to add a new document to the User array. I am doing this by above code but its not working.Please tell me the right way of doing it.

I don't understand your document structure at all... and the only "user" array I could find in here was a field called "3". Your code does in fact work and appends a document into the "3" array. The below is the result after running your code. Perhaps you could be more clear as to what you want your document to look like after you have "appended" a user.
{
"_id":ObjectId("4fa7d965ce48f3216c52c6c7"),
"name":"himani",
"3":[
{
"1":"heena",
"2":"divya",
"values":[ 2, 5 ]
},
{
"count":"2"
}
]
}

Related

Conditional Query based on Variable value in MongoDB

I am building a list view page with multiple filters using .net core as backend and mongodb as database. I want to filter data based on some condition such that if the variable is passed as blank, it should retrieve all data, otherwise only the matching data.
In mssql this can be achieved easily by
where (#SymbolCode = '' or SymbolCode = #SymbolCode)
What is the option in mongodb filter
var filter = new BsonDocument
{
{
"symbolCode", SymbolCodeSearchString // If string SymbolCodeSearchString is blank, it should retrieve all data else the search data
}
};
Sample Data
{
"_id": {
"$oid": "60ed91bc65675f966c0eec46"
},
"symbolCode": "F",
"timestamp": {
"$date": "2021-07-13T13:14:35.909Z"
}
}
you should check symboleCode before query on mongodb
first check if symbolCode is empty or ""
define filter query as
var filter = new BsonDocument
{
};
else if it was not empty
var filter = new BsonDocument
{
{
"symbolCode", SymbolCodeSearchString // If string SymbolCodeSearchString is blank, it should retrieve all data else the search data
}
};
I was able to figure out. Thanks to #Naimi and #Takis. Building a dynamic filter is the key. Posting here the answer so that it could help anyone
var filterQuery = new BsonDocument
{
{
"symbolCode", new BsonDocument
{
{ "$regex", SymbolCodeString},
{ "$options", "i"}
}
}
};
if (fromDate != "" && toDate != "")
{
BsonElement dateFilter = new("timestamp", new BsonDocument
{
{ "$gt", fromDate},
{ "$lt", toDate}
});
filterQuery.Add(dateFilter);
}
By this way, i am able to add any number of filters dynamically

How to compare two collections and archive documents which are not common

I have two collections for example CollectionA and CollectionB both have common filed which is hostname
Collection A :
{
"hostname": "vm01",
"id": "1",
"status": "online",
}
Collection B
{
"hostname": "vm01",
"id": "string",
"installedversion": "string",
}
{
"hostname": "vm02",
"id": "string",
"installedversion": "string",
}
what i want to achieve is when i receive a post message for collection B
I want to check if the record exists in Collection B based on hostname and update all the values. if not insert the new record ( i have read it can be achieved by using upsert -- still looking how to make it work)
I want to check if the hostname is present in Collection A , if not move the record from collection B to another collection which is collection C ( as archive records).ie in the above hostname=vm02 record from collection B should be moved to collectionC
how can i achieve this using springboot mongodb anyhelp is appreciated.The code which i have to save the Collection B is as follows which i want to update to achieve the above desired result
public RscInstalltionStatusDTO save(RscInstalltionStatusDTO rscInstalltionStatusDTO) {
log.debug("Request to save RscInstalltionStatus : {}", rscInstalltionStatusDTO);
RscInstalltionStatus rscInstalltionStatus = rscInstalltionStatusMapper.toEntity(rscInstalltionStatusDTO);
rscInstalltionStatus = rscInstalltionStatusRepository.save(rscInstalltionStatus);
return rscInstalltionStatusMapper.toDto(rscInstalltionStatus);
}
Update 1 : The below works as i expected but I think there should be a better way to do this.
public RscInstalltionStatusDTO save(RscInstalltionStatusDTO rscInstalltionStatusDTO) {
log.debug("Request to save RscInstalltionStatus : {}", rscInstalltionStatusDTO);
RscInstalltionStatus rscInstalltionStatus = rscInstalltionStatusMapper.toEntity(rscInstalltionStatusDTO);
System.out.print(rscInstalltionStatus.getHostname());
Query query = new Query(Criteria.where("hostname").is(rscInstalltionStatus.getHostname()));
Update update = new Update();
update.set("configdownload",rscInstalltionStatus.getConfigdownload());
update.set("rscpkgdownload",rscInstalltionStatus.getRscpkgdownload());
update.set("configextraction",rscInstalltionStatus.getConfigextraction());
update.set("rscpkgextraction",rscInstalltionStatus.getRscpkgextraction());
update.set("rscstartup",rscInstalltionStatus.getRscstartup());
update.set("installedversion",rscInstalltionStatus.getInstalledversion());
mongoTemplate.upsert(query, update,RscInstalltionStatus.class);
rscInstalltionStatus = rscInstalltionStatusRepository.findByHostname(rscInstalltionStatus.getHostname());
return rscInstalltionStatusMapper.toDto(rscInstalltionStatus);
}
Update2 : with the below code i am able to get move the records to another collection
String query = "{$lookup:{ from: \"vmdetails\",let: {rschostname: \"$hostname\"},pipeline:[{$match:{$expr:{$ne :[\"$hostname\",\"$$rschostname\"]}}}],as: \"rscInstall\"}},{$unwind:\"$rscInstall\"},{$project:{\"_id\":0,\"rscInstall\":0}}";
AggregationOperation rscInstalltionStatusTypedAggregation = new CustomProjectAggregationOperation(query);
LookupOperation lookupOperation = LookupOperation.newLookup().from("vmdetails").localField("hostname").foreignField("hostname").as("rscInstall");
UnwindOperation unwindOperation = Aggregation.unwind("$rscInstall");
ProjectionOperation projectionOperation = Aggregation.project("_id","rscInstall").andExclude("_id","rscInstall");
OutOperation outOperation = Aggregation.out("RscInstallArchive");
Aggregation aggregation = Aggregation.newAggregation(rscInstalltionStatusTypedAggregation,unwindOperation,projectionOperation,outOperation);
List<BasicDBObject> results = mongoTemplate.aggregate(aggregation,"rsc_installtion_status",BasicDBObject.class).getMappedResults();
this issue which i have here is it returns multiple records
Found the solution , there may be other best solutions but for me this one worked
create a class customeAggregationGeneration (found in SO answers and extended to match my needs)
public class CustomProjectAggregationOperation implements AggregationOperation {
private String jsonOperation;
public CustomProjectAggregationOperation(String jsonOperation) {
this.jsonOperation = jsonOperation;
}
#Override
public Document toDocument(AggregationOperationContext aggregationOperationContext) {
return aggregationOperationContext.getMappedObject(Document.parse(jsonOperation));
}
}
String lookupquery = "{$lookup :{from:\"vmdetails\",localField:\"hostname\",foreignField:\"hostname\"as:\"rscinstall\"}}";
String matchquery = "{ $match: { \"rscinstall\": { $eq: [] } }}";
String projectquery = "{$project:{\"rscinstall\":0}}";
AggregationOperation lookupOpertaion = new CustomProjectAggregationOperation(lookupquery);
AggregationOperation matchOperation = new CustomProjectAggregationOperation(matchquery);
AggregationOperation projectOperation = new CustomProjectAggregationOperation(projectquery);
Aggregation aggregation = Aggregation.newAggregation(lookupOpertaion, matchOperation, projectOperation);
ArrayList<Document> results1 = (ArrayList<Document>) mongoTemplate.aggregate(aggregation, "rsc_installtion_status", Document.class).getRawResults().get("result");
// System.out.println(results1);
for (Document doc : results1) {
// System.out.print(doc.get("_id").toString());
mongoTemplate.insert(doc, "RscInstallArchive");
delete(doc.get("_id").toString());

Phrase query in Lucene 6.2.0

I have a document like this:
{
"_id" : ObjectId("586b723b4b9a835db416fa26"),
"name" : "test",
"countries" : {
"country" : [
{
"name" : "russia iraq"
},
{
"name" : "USA china"
}
]
}
}
In MongoDB I am trying to retrieve it using phrase query(Lucene 6.2.0). My code looks as folllows:
StandardAnalyzer analyzer = new StandardAnalyzer();
// 1. create the index
Directory index = new RAMDirectory();
IndexWriterConfig config = new IndexWriterConfig(analyzer);
try {
IndexWriter w = new IndexWriter(index, config);
MongoClient client = new MongoClient("localhost", 27017);
DB database = client.getDB("test123");
DBCollection coll = database.getCollection("test1");
//MongoCollection<org.bson.Document> collection = database.getCollection("test1");
DBCursor cursor = coll.find();
System.out.println(cursor);
while (cursor.hasNext()) {
BasicDBObject obj = (BasicDBObject) cursor.next();
Document doc = new Document();
BasicDBObject f = (BasicDBObject) (obj.get("countries"));
List<BasicDBObject> dts = (List<BasicDBObject>)(f.get("country"));
doc.add(new TextField("id",obj.get("_id").toString().toLowerCase(), Field.Store.YES));
doc.add(new StringField("name",obj.get("name").toString(), Field.Store.YES));
doc.add(new StringField("countries",f.toString(), Field.Store.YES));
for(BasicDBObject d : dts){
doc.add(new StringField("country",d.get("name").toString(), Field.Store.YES));
//
}
w.addDocument(doc);
}
w.close();
and my search goes like :
PhraseQuery query = new PhraseQuery("country", "iraq russia" );
// 3. search
int hitsPerPage = 10;
IndexReader reader = DirectoryReader.open(index);
IndexSearcher searcher = new IndexSearcher(reader);
TopDocs docs = searcher.search(query, hitsPerPage);
ScoreDoc[] hits = docs.scoreDocs;
// 4. display results
System.out.println("Found " + hits.length + " hits.");
for(int j=0;j<hits.length;++j) {
int docId = hits[j].doc;
Document d = searcher.doc(docId);
System.out.println(d);
}
reader.close();
}
catch (Exception e) {
e.printStackTrace();
}
I am getting zero hits for this query. Can anyone tell what I am doing wrong?
jars used:
lucene-queries4.2.0
lucene-queryparser-6.2.1
lucene-analyzers-common-6.2.0
i made certain changes which goes like:
Query query = new PhraseQuery.Builder()
.add(new Term("country", "iraq"))
.add(new Term("country", "russia"))
.setSlop(2)
.build();
and also i changed the type of feild while indexing :
for(BasicDBObject d : dts){
doc.add(newTextField("country",d.get("name").toString(), Field.Store.YES));
}
But can anyone tell me the difference between StringFeild and TextFeild while indexing?
Firstly, never mix Lucene versions. All your jars should be the same version. Upgrade lucene-queries to 6.2.1. In practice you might or might not run into trouble mixing up 6.2.0 and 6.2.1, but you definitely should upgrade lucene-analyzers-common as well.
PhraseQuery doesn't analyze for you, you have to add terms to it separately. In your example, "iraq russia" is treated as a single terms, rather than two separate (analyzed) terms.
It should look something like this:
Query query = new PhraseQuery.Builder()
.add(new Term("country", "iraq"))
.add(new Term("country", "russia"))
.build();
If you want something that will analyze for you, you can use the QueryParser:
QueryParser parser = new QueryParser("country", new StandardAnalyzer())
Query query = queryparser.parse("\"iraq russia\"");

In Meteor, simple Collection.find().fetch() is returning an empty array

here is my code. Could anyone please help me out in knowing why the value of rekt on the runtime is an empty array? On my meteor all find().fetch() are returning an empty array only. Does anyone have any experience with this sort of a thing.
PlayersList = new Mongo.Collection('players');
rekt = PlayersList.find().fetch();
console.log(rekt);
ids = new Object();
sorted = new Object();
oldq = new Object;
try
{
rs1 = {name : "Sam"};
PlayersList.update(rs1 , {$set: {name : "Sam" , score : 100}} , {upsert:true});
console.log(resultset);
}catch(e)
{}
function selectscore(cutoff)
{
var oldq = PlayersList.find().fetch();
for(var a in oldq)
{
elm = oldq[a];
if(elm.score<=cutoff)
{
sorted[elm.name] = elm.score;
}
}
return sorted;
}
if (Meteor.isClient) {
oldq = PlayersList.find().fetch();
for(var a in oldq)
{
elm = oldq[a];
ids[elm.name] = elm._id;
}
selectscore(50);
// counter starts at 0
Session.setDefault('counter', 0);
Template.hello.helpers({
counter: function () {
return Session.get('counter');
}
});
Template.hello.events({
'click button': function () {
// increment the counter when button is clicked
Session.set('counter', Session.get('counter') + 1);
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
PlayersList.update({name:"Bob"} , {$set:{name: "Mob", score: 500}});
PlayersList.update({name:"Mob"} , {$set:{name: "Cobb", score: 5000}});
resultset = PlayersList.find().fetch();
//console.log(resultset.attr(_id));
rs = {name : "Slobb"};
PlayersList.update({name:"Cobb"} , {$set:{name: "Slobb", score: 50000}});
PlayersList.update( rs, {$set:{name: "Bob", score: 50}});
newq = PlayersList.find().fetch();
});
}
Thanks in advance.
You are logging the same result twice. The array returned by fetch isn't reactive. Meaning, when you fetch and then insert, the array wont change. So try replacing the second console.log(resultset); with PlayersList.find().fetch();. Also, set up the proper publish/subscribe functions, (as #Paul described).
it appears that there is some issue here not allowing the find().fetch() functions to return the object array. I tried kriegs solution but it did not work as well. I finally managed to solve the problem using Deps.autorun.
Thanks all

How to make the time stamp difference for inserting and updating record in mongo?

I need to create a time stamp in my mongodb collection. Am using C# in front end .My code is :
internal static void CreateStudent(string Id, string Name,string strUserId)
{
MongoServer server = MongoServer.Create(ConnectionString);
MongoDatabase mydb = server.GetDatabase("Database");
MongoCollection<BsonDocument> Student = mydb.GetCollection<BsonDocument>("Student");
BsonDocument colectionGenre = new BsonDocument {
{ "Code", Id }, //Id is Auto Generated in sql. Fetch from there using Output parameter and save it in one variable and pass that here
{ "Name", Name },
{ "Status","Y"},
{"stamps" , new BsonDocument {
{"Ins_date", DateTime.Now},
{"up_date",""},
{"createUsr", strUserId},
{"updUsr", ""},
{"Ins_Ip", GetIP()},
{"Upd_IP",""}}}
};
Student.Insert(colectionGenre);
}
internal static void UpdateStudent(string Id, string Name,string strUserId)
{
MongoServer server = MongoServer.Create(ConnectionString);
MongoDatabase mydb = server.GetDatabase("Database");
MongoCollection<BsonDocument>Student = mydb.GetCollection<BsonDocument>("Student"); ;
// Query for fetch the ID which is edited by the User...(user can only able to edit the NAME field alone)
var query = new QueryDocument {
{ "Code", Id }};
// After Fetch the correspondent ID it updates the name with the Edited one
var update = new UpdateDocument {
{ "$set", new BsonDocument("Name", Name) }
};
// Updated Query.(Id is same as previous. Name is updated with new one)
{"stamps" , new BsonDocument {
{"up_date",DateTime.Now},
{"updUsr", strUserId},
{"Upd_IP",GetIp()}}}
}}
};
Student.Update(query,update,UpdateFlags.Upsert, SafeMode.True);
}
It works fine for INSERT method with time(Stamp) once the record is created. But the problem is with update method. When user update something the insert time also changed with the updated time..
After User Updates the Name, i want my will collection looks like this
{
"_id" : ObjectId("5178aea4e6d8e401e8e51dc0"),
"Code": 12,
"Name": Sname,
"Stamps:"{
"Ins_date":03:34:00,
"up_date": 04:35:12
}
}
But my problem is both the time will same after update. That is because it takes the current date and time function..How can i achieve the above output.It needs any driver.Suggest something for me...
You're passing in a value for the Ins_date field when you're updating the document. Just remove that from the update document and it won't change it.
var update = new UpdateDocument {
{"$set", new BsonDocument {
{"State_strName", name},
{"stamps" , new BsonDocument {
{"up_date",DateTime.Now},
{"createUsr", ""},
{"updUsr", ""},
{"Ins_Ip", GetIP()},
{"Upd_IP",GetIP()}}}
};
tblmytbl.Update(query, update);
How you are updating the value in the existing document by using unique id or other unique value.Check whether the unique id or value is already exist in your database documents.If it is exist means change the update time only don't do anything..
While updating the data in mongoDB,you are passing the same values for Ins_date and up_date i.e. DateTime.Now(current system date and time).So the same values are updating in your monoDB document.
For this you can do one thing :-
Before updating your mongoDB document you take Ins_date values from your database by using sql query in C#.net and then use this value for Ins_date and for up_date use DateTime.Now then your both values will be different.
var update = new UpdateDocument {
{"$set", new BsonDocument {
{"State_strName", name},
{"stamps" , new BsonDocument {
{"Ins_date", **Ins_date values_from your database**} ,
{"up_date",DateTime.Now},
{"createUsr", ""},
{"updUsr", ""},
{"Ins_Ip", GetIP()},
{"Upd_IP",GetIP()}}}
};
tblmytbl.Update(query, update);
Sounds like what you need is the new $setOnInsert operator which was added in 2.4 for exactly this use case.
When the update with upsert flag results in an insert, you want to $set insert_date to Date.now but when it's a regular update, you don't want to set it at all. So now with your update you should use $set for regular fields you want to set whether it's an update or an insert, but use $setOnInsert for fields that should only be set during insert.
Finally I got answer...In INSERT method Simply pass the below things
{"Insert-stamps" , new BsonDocument {
{"Ins_date", DateTime.Now},
{"createUsr", strUserId},
{"Ins_Ip", GetIP()}}},
{"Update-stamps" , new BsonDocument {
{"up_date",""},
{"updUsr", ""},
{"Upd_IP",""}}}
And In UPDATE method
{"Update-stamps" , new BsonDocument {
{"up_date", DateTime.Now},
{"updUsr", StrUserId},
{"Upd_IP",GetIP()}}}
It works Fine for my standard....